Haskell 也许你没有';对一个函数应用的参数是否足够?
我在大学的一门课程中学习Haskell,有一个考试练习,我们需要定义一个函数,它包含一系列函数Haskell 也许你没有';对一个函数应用的参数是否足够?,haskell,Haskell,我在大学的一门课程中学习Haskell,有一个考试练习,我们需要定义一个函数,它包含一系列函数[(Int->Int)]和另一个Int类型的参数,并返回一个Int。所以类型应该是 compose :: [(Int ->Int)] -> Int -> Int. 函数应该从左到右返回列表中函数的组合,并将其应用于第二个参数。 我尝试了以下方法: compose :: [(Int -> Int)] -> Int -> Int compose [] x = x com
[(Int->Int)]
和另一个Int
类型的参数,并返回一个Int
。所以类型应该是
compose :: [(Int ->Int)] -> Int -> Int.
函数应该从左到右返回列表中函数的组合,并将其应用于第二个参数。
我尝试了以下方法:
compose :: [(Int -> Int)] -> Int -> Int
compose [] x = x
compose (f:fs) x
|fs == [] = f x
|f : (compose fs x)
但是编译器抛出一个错误:
003Exam.hs:24:22:
Couldn't match expected type ‘Int’ with actual type ‘[Int -> Int]’
In the expression: f : (compose fs x)
In an equation for ‘compose’:
compose (f : fs) x
| fs == [] = f x
| otherwise = f : (compose fs x)
003Exam.hs:24:28:
Couldn't match expected type ‘[Int -> Int]’ with actual type ‘Int’
In the second argument of ‘(:)’, namely ‘(compose fs x)’
In the expression: f : (compose fs x)
如果我离开最后一行,比如:
compose :: [(Int -> Int)] -> Int -> Int
compose [] x = x
compose (f:fs) x
|fs == [] = f x
然后我也得到了一个错误-这是一个我真的不明白的错误:
003Exam.hs:23:13:
No instance for (Eq (Int -> Int))
(maybe you haven't applied enough arguments to a function?)
arising from a use of ‘==’
In the expression: fs == []
In a stmt of a pattern guard for
an equation for ‘compose’:
fs == []
In an equation for ‘compose’: compose (f : fs) x | fs == [] = f x
我很高兴能得到任何帮助,澄清我做错了什么
|f : (compose fs x)
^
我想你的问题是这个冒号不应该在这里。
Haskell中的
:
是列表构造函数,这就是为什么编译器告诉您正在尝试返回[Int->Int]
。如果它不在那里,f将被简单地应用,并且您将返回一个Int
,您必须对结果重复应用函数,并且空函数列表应被视为id
Prelude> let comp :: [(Int->Int)] -> Int -> Int
Prelude| comp [] x = x
Prelude| comp (f:fs) x = comp fs (f x)
Prelude|
Prelude> comp [(^2),(+1)] 3
10
我看错了问题,上面是从左到右应用函数。如果你是从左到右作曲(首先应用最右边的函数),应该是这样的(现在是无点)
首先,(:)
仅用于在列表前面添加元素(或与这些元素匹配的模式),因此必须替换
f : compose fs x
与
接下来,您必须在保护中使用类型为Bool
的表达式或模式匹配:
| fs == [] = -- this line is still wrong, see below
| otherwise = f (compose f xs)
但是,没有函数的Eq
实例。两个函数的等价性是不可判定的(通常),因此使用null::[a]->Bool
而不是(==)::Eq a=>[a]->[a]->Bool
:
compose :: [(Int -> Int)] -> Int -> Int
compose [] x = x
compose (f:fs) x
| null fs = f x
| otherwise = f (compose fs x)
由于compose[]x
与x
相同,您甚至可以删除该复选框:
compose :: [(Int -> Int)] -> Int -> Int
compose [] x = x
compose (f:fs) x = f (compose fs x)
练习
- 扩展
(用其定义替换它),而不删除中间术语。你注意到一种模式了吗compose[(+1),(+2)]1
- 这个模式会让你想起库函数吗
- 尝试使用该库函数来编写
compose
import Data.Monoid (Dual (..))
import Control.Category (Category (..))
import Data.Foldable (Foldable (foldMap))
import Prelude hiding (id, (.))
接下来,一个类型解释了幺半群是一个只有一个对象的类别:
newtype Cat c a = Cat { getCat :: c a a }
instance Category c => Monoid (Cat c a) where
mempty = Cat id
mappend (Cat f) (Cat g) = Cat (f . g)
最后,您寻找的函数,从->
概括为任意类别
:
compose1 :: (Foldable f, Category c) => f (c a a) -> c a a
compose1 = getCat . foldMap Cat
compose2 :: (Foldable f, Category c) => f (c a a) -> c a a
compose2 = getCat . getDual . foldMap (Dual . Cat)
读者练习:编写等效函数,将类别
替换为半群体
,将可折叠
替换为可折叠
读者的另一个练习是:使用Data.concure.concure
和/或#.
和#
从Data.Profunctor.Unsafe
编写幺半群(Cat c a)
实例,以避免错误的闭包分配
另外,
Cat
类型只能解释一半的情况。以下是剩下的:
newtype Mon m a b = Mon m
instance Monoid m => Category (Mon m) where
id = Mon mempty
Mon m . Mon n = Mon (m `mappend` n)
可以说,使用它会更精确
data Mon m a b where
Mon :: m -> Mon m a a
但是如果没有真正增加太多的价值,这将是效率较低的。关于
fs=[]
和“没有(Eq(Int->Int))的实例”还有另一个问题,这改变了原始函数的语义,因为comp[negate,(+2)]3
在问题中是-5
,但在您的变体中是-1
。哇,非常感谢大家。我刚吃了一些意大利面条,当我回到这里时,有很多定性的答案。现在我相信我明白了问题所在。非常感谢。(我想你是说折叠?):谢谢all@DavidJambalaya不客气。请注意,这样其他人就知道您的问题已经得到了回答。您可以随时更改已接受的答案。aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa。是的,这是一个褶皱。不过,我不会告诉你是哪一个:D.你说的“哪一个折叠”是什么意思foldMap
无论如何都会成功@dfeuerfoldMap Endo
是一个巧妙的技巧;/对于新手来说,这是一种黑暗魔法用<代码>折叠*>代码>你几乎是按PART/如果你用<代码> L>代码>或<代码> R>代码>来代替<代码> */COD>。至少直到默认的书籍使用后FTP材质。你的答案是完全脱钩的。请不要将此视为批评/但你的回答离题了。我不确定它们走了多远,但考虑到语法错误,我认为它们没有处理可折叠的
或幺半群
。另外,如果你没有回答最初的问题,你正在使用轨道加农炮射杀一棵树,但有点错过了。毕竟,compose1=foldr(.)id
和compose2=foldr(flip(.)id
(带有Control.Category
)。好吧,不是100%偏离主题,你提供了一个有效的compose
,但你明白了我的意思(而且“评论”的押韵真的很好;但你不知道我最近为什么要押韵)。@Zeta,这不太正确,例如,由于无限snoc列表可能使用我的代码在某些类别中给出结果,但从不使用foldr
。当然,可能应该添加“在这个问题的上下文中”。对于“如何将可折叠的
中的自同态折叠为单个自同态”,您的答案非常准确。(你不需要偶尔睡觉吗?@Zeta,我试过了,但我不太擅长在合理的时间睡觉。
newtype Mon m a b = Mon m
instance Monoid m => Category (Mon m) where
id = Mon mempty
Mon m . Mon n = Mon (m `mappend` n)
data Mon m a b where
Mon :: m -> Mon m a a