首页 > 解决方案 > 用函数组合理解map函数

问题描述

我有以下 Haskell 表达式:

let increment x = 1 + x
in \xs -> map chr (map increment (map ord xs))

我知道上面的表达式需要一个列表,并将ord函数应用于列表中的每个元素。对于字符列表,结果将是整数列表(ASCII 值)。然后该increment函数将列表中的每个整数加 1。chr然后该函数将每个整数转换回其对应的字符。

我也有以下表达:

map chr . map (1+) . map ord

我试图弄清楚上面是否等同于第一个表达式。但是,当我在 GHCI 中尝试上述表达式时,出现错误:

map chr . map (1+) . map ord ['a', 'b', 'c', 'd', 'e']

我不确定为什么表达式不起作用。由于使用了函数组合,因此表达式不会被评估为:

(map chr (map (1+) (map ord ['a', 'b', 'c', 'd', 'e'])))

得到map (1+)一个列表作为结果map ord,并map chr得到一个列表作为结果map (1+)

标签: haskellfunctional-programminghigher-order-functions

解决方案


运算符(定义为名称中没有字母数字字符的函数,用于中缀样式)的优先级低于 Haskell 中的其他函数。因此你的表达:

map chr . map (1+) . map ord ['a', 'b', 'c', 'd', 'e']

被解析为:

(map chr) . (map (1+)) . (map ord ['a', 'b', 'c', 'd', 'e'])

这没有任何意义 -.运算符结合了 2 个函数,map ord ['a', 'b', 'c', 'd', 'e']不是一个函数,而是一个数字列表。

但是对于带有所有嵌套括号的正确版本,仍然有更好的选择。您要做的是从字符列表开始,然后依次map执行 3 个函数。根据函数组合的定义,这与将 3map的组合应用于它相同,即:

(map chr . map (1+) . map ord) ['a', 'b', 'c', 'd', 'e']

正如@chi 在下面指出的那样,通常会这样写,使用函数应用运算符$(其优先级低于任何其他运算符)以避免需要任何括号:

map chr . map (1+) . map ord $ ['a', 'b', 'c', 'd', 'e']

并且,因为map f . map g总是相同map (f . g)(当你停下来思考这些表达式的含义时,这应该是显而易见的——这也是map操作必须满足的基本定律才能使列表类型变为 a Functor),这也可以写成:

map (chr . (1+) . ord) ['a', 'b', 'c', 'd', 'e']

在我看来,这是最好的和最易读的版本。

尽管更好,正如@chi 再次指出的那样,使用chr . (1+) . ord相当于succ的内置函数来获取可枚举类型的“下一个”值。所以你可以写map succ ['a', 'b', 'c', 'd', 'e']


推荐阅读