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
作为函数f
、g
和h
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
我刚开始在大学学习 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
作为函数f
、g
和h
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