Difference between composition and function application
99个haskell问题的第一个问题是"查找列表的最后一个元素"。我想出了两个解决方案:
解决方案1(这项工作)
解决方案2(不起作用)
问题
- 为什么解决方案1有效,而不是解决方案2?我最困惑的是两个实现如何提供模式匹配。
head是一个论点1的函数。如果你用f $ x把一个函数应用到某个东西上,这和简单地写f x是一样的(或者如果你喜欢f(x)或(f)x是一样的……更丑):参数由指定的变量"填充"。因此,head $ reverse的结果只是head给你的任何结果,当用reverse类型的论点时……但这不起作用,因为head需要一个列表,而reverse是一个函数。$本身并不关心这个问题,只关心参数,例如您可以编写
Prelude> :t map $ reverse
map $ reverse :: [[a]] -> [[a]]
因为map的第一个参数实际上是一个函数。
与(.)不同。这关系到右边的参数有什么类型(也必须是一个函数),并且它不会直接将它提供给左边的函数。相反,f . g生成另一个函数,它执行以下操作:等待x的某个参数,它将该参数反馈给g,然后将该参数的结果反馈给f。
现在,如果你写
也就是说,你把myLast定义为(.)给你的函数,它是head和reverse的组合。这里没有提到关于myLast的参数,这并不重要:[a] -> a只是一种类型,所以您可以用这种类型定义变量(比如mylast),将它们分配给恰好具有这种函数类型的值(比如head . reverse)。如果需要,可以显式地设置参数:
请注意,之所以需要parens,是因为它被解析为head . (reverse x),这是不起作用的,因为reverse x不再是一个函数,只是一个结果列表。因此,你不能用head组合它;但是你可以做的是将head应用于它:
实际上,haskell中的每个函数只有一个参数…但是我们对(+) :: Int -> Int -> Int这样的东西说"双参数函数",尽管实际上这是一个返回单参数函数的单参数函数,返回Int:(+) :: Int -> (Int -> Int)。
大致上,应用程序($用于函数与其参数(本例中为列表)之间,而组合(.用于两个函数之间。
关于模式匹配:在第一个解决方案中,函数reverse将为您执行所需的模式匹配,因此myLast不必执行。