Haskell 函数组合方法

Haskell function composition methods

我刚开始在大学学习 Haskell,在玩它的过程中,我偶然发现了一个我似乎无法理解的问题。 下面的代码给了我想要的结果:

import Data.List
list = ["Hello", "world"]

main = print $ intercalate " something " (reverse (map reverse list))

输出:

"dlrow something olleH"

但是我想用点而不是括号来编写 'main' 函数,所以它尝试了:

main = print $ intercalate " something " . reverse . map reverse list

但是,这给了我以下错误:

test.hs:5:54: error:
    • Couldn't match expected type ‘a0 -> [[Char]]’
                  with actual type ‘[[Char]]’
    • Possible cause: ‘map’ is applied to too many arguments

我以为这些点和括号的意思完全一样:函数组合。为什么括号有效,而点给我一个与类型相关的错误?任何帮助将不胜感激!

使用 . 的函数组合意味着函数将有另一个参数。如果您改为编写以下内容,它会起作用。

main = print $ (intercalate " something " . reverse . map reverse) list

这样,list 值就是括号内函数的参数。

函数组合等价如下:

main = print (intercalate " something " (reverse (map reverse list)))
main = print (intercalate " something " ((reverse . map reverse) list))
main = print ((intercalate " something " . (reverse . map reverse)) list)
main = (print . (intercalate " something " . (reverse . map reverse))) list

或者,删除不必要的括号:

main = (print . intercalate " something " . reverse . map reverse) list
main = print . intercalate " something " . reverse . map reverse $ list

在您的尝试中,map reverse list 是单个表达式,即中缀 . 运算符的参数,它不起作用 - 您只能编写 map reverse 函数,并且然后将整个组合函数应用于 list 参数。

括号不代表函数组合。它们只是表示“将这个子表达式分组”。当然你可以使用它们来组成一个函数组合链:下面定义c作为函数fgh

c x = f (g (h x))

这也可以写成:

c = f . g . h

因此,您可以

main = print $ c list
 where c = intercalate " something " . reverse . map reverse

但是如果你再次内联 c,你需要注意不要弄乱解析规则:只在组合链的右边写 list 是行不通的,因为函数application 比任何中缀运算符(包括 .)绑定得更紧密,尽管它实际上是最紧密的中缀运算符。即,

intercalate " something " . reverse . map reverse list

实际解析为

(intercalate " something ") . (reverse) . (map reverse list)

但这不是你想要的。您需要确保 list 实际上是整个组合链的参数,而不仅仅是它的最后一个元素;首选的方法是使用 $ 运算符:

intercalate " something " . reverse . map reverse $ list

$ 具有 最低 的优先级,因此这被解析为

((intercalate " something ") . (reverse) . (map reverse)) (list)

或者,您可以立即将 map reverse 应用于 list – 这本身并没有错,只是结果不再是组合链的一部分:

intercalate " something " . reverse $ map reverse list