haskell - 用函数组合理解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+)
?
解决方案
运算符(定义为名称中没有字母数字字符的函数,用于中缀样式)的优先级低于 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']
推荐阅读
- mysql - 对原始查询 TextRow 进行续集并从中获取数据
- html - 启用跨多个 html 页面的搜索
- reactjs - 为什么我的 props 在我更新状态之前就更新了?
- apache-nifi - 如何替换整个 Flowfile 内容?
- javascript - 如何修复“ReferenceError:找不到变量:socket”和“ReferenceError:找不到变量:require”?
- python - tensorflow可以扫描并只保留最终结果吗?
- android - 将应用程序数据库与 Google Drive 同步 - 算法/逻辑
- python - 为什么我的代码中出现类型错误?
- javascript - 为什么线性搜索的 array.forEach() 实现不起作用?
- java - 如何编写一个while循环