haskell - 理解这个任务?
问题描述
为了刷新我 20 年使用 Haskell 的经验,我正在浏览https://en.wikibooks.org/wiki/Write_Yourself_a_Scheme_in_48_Hours/Adding_Variables_and_Assignment,并且在某一时刻引入了以下行以应用于op
所有参数。这是为了实现例如(+ 1 2 3 4)
numericBinop op params = mapM unpackNum params >>= return . Number . foldl1 op
语法我看不懂,文中的解释有点含糊。
我了解什么foldl1
以及如何点函数(unpackNum
是一个辅助函数),但是使用 Monads 和>>=
运算符让我有点困惑。
这要怎么读?
解决方案
本质上,
mapM unpackNum params >>= return . Number . foldl1 op
由两部分组成。
mapM unpackNum params
意思是:获取参数列表params
。在每个项目上, apply :这将在monad 中unpackNum
产生一个Integer
包裹。ThrowsError
所以,它并不完全是一个 plain Integer
,因为它有可能出错。无论如何,unpackNum
在每个项目上使用要么成功产生 all Integers
,要么引发一些错误。在第一种情况下,我们生成一个新的 type 列表[Integer]
,在第二种情况下,我们(不出所料)抛出错误。因此,这部分的结果类型是ThrowsError [Integer]
.
第二部分是... >>= return . Number . foldl1 op
。这里>>=
的意思是:如果第一部分抛出了一些错误,整个表达式也会抛出那个错误。如果该部分成功生成,[Integer]
则继续foldl1 op
,将结果包装为Number
,最后使用return
注入此值作为成功计算。
总的来说,有单子计算,但你不应该考虑太多。这里的 monadic 东西只是传播错误,或者如果计算成功则存储纯值。有了一点经验,就可以只专注于成功的值,而让mapM,>>=,return
处理错误的情况。
顺便说一句,请注意,虽然本书使用类似 的代码action >>= return . f
,但这可以说是一种糟糕的风格。可以使用 , 达到同样的效果,fmap f action
或者f <$> action
,这是表达相同计算的一种更直接的方式。例如
Number . foldl1 op <$> mapM unpackNum params
这非常接近忽略错误情况的非单子代码
-- this would work if there was no monad around, and errors did not have to be handled
Number . foldl1 op $ map unpackNum params
推荐阅读
- amazon-web-services - 如何从 AWS Athena 访问成本分配标签数据
- excel - 如何使用 VBA 在 Excel 宏中删除具有两列的重复项?
- neo4j - Neo4j 关系
- bootstrap-4 - 输入“中心”在 Bootstrap 4 中不起作用
- java - 休息断言问题 java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory java gradle
- c - 线程 1:从链表中删除时的 EXC_BAD_ACCESS
- python - 尝试反转字符串时的空白输出
- python - VSC vs PyCharm 自动完成选项卡:它可以填充函数、括号并退出该行吗?
- c# - 再一次,如何在 C# 中处理一个巨大的集合
- rust - 反序列化 reqwest 查询错误 rustc(E0308)