cen*_*980 0 haskell functional-programming higher-order-functions
我有以下Haskell表达式:
let increment x = 1 + x
in \xs -> map chr (map increment (map ord xs))
Run Code Online (Sandbox Code Playgroud)
我知道上面的表达式接受一个列表,并将ord函数应用于列表中的每个元素。对于字符列表,结果将是整数列表(ASCII值)。然后,increment函数将列表中的每个整数递增1。然后,chr函数将每个整数转换回其对应的字符。
而且我还有以下表达式:
map chr . map (1+) . map ord
Run Code Online (Sandbox Code Playgroud)
我试图弄清楚上面是否等于第一个表达式。但是,当我在GHCI中尝试上述表达式时,出现错误:
map chr . map (1+) . map ord ['a', 'b', 'c', 'd', 'e']
Run Code Online (Sandbox Code Playgroud)
我不确定为什么该表达方式无效。由于使用了函数组合,因此该表达式不会被评估为:
(map chr (map (1+) (map ord ['a', 'b', 'c', 'd', 'e'])))
Run Code Online (Sandbox Code Playgroud)
随着map (1+)越来越列表作为的结果map ord,并map chr得到一个列表作为的结果map (1+)?
运算符(定义为名称中没有字母数字字符的函数,以中缀样式使用)的优先级低于Haskell中的其他函数。因此,您的表达:
map chr . map (1+) . map ord ['a', 'b', 'c', 'd', 'e']
Run Code Online (Sandbox Code Playgroud)
解析为:
(map chr) . (map (1+)) . (map ord ['a', 'b', 'c', 'd', 'e'])
Run Code Online (Sandbox Code Playgroud)
而且这没有任何意义- .运算符组合了2个功能,map ord ['a', 'b', 'c', 'd', 'e']不是一个功能,而是一个数字列表。
但是,对于带有所有嵌套括号的正确版本,还有更好的选择。您想要做的是从字符列表开始,并map在其上依次执行3个功能。根据功能组合的定义,这与对其应用3 maps 的组合相同,即:
(map chr . map (1+) . map ord) ['a', 'b', 'c', 'd', 'e']
Run Code Online (Sandbox Code Playgroud)
就像@chi指出的那样,通常使用函数应用程序运算符$(其优先级低于任何其他运算符)编写成这样,以避免需要任何括号:
map chr . map (1+) . map ord $ ['a', 'b', 'c', 'd', 'e']
Run Code Online (Sandbox Code Playgroud)
并且,由于map f . map g始终相同map (f . g)(当您停止考虑这些表达式的含义时这很明显-这也是map操作要使列表类型成为a所必须满足的基本定律Functor),因此可以替换为:
map (chr . (1+) . ord) ['a', 'b', 'c', 'd', 'e']
Run Code Online (Sandbox Code Playgroud)
我认为这是最好,最易读的版本。
尽管@chi再次指出,更好的方法是使用chr . (1+) . ord等效于succ的内置函数,以获取可以枚举的类型的“下一个”值。所以你可以写map succ ['a', 'b', 'c', 'd', 'e']