首页 > 解决方案 > 理解这个任务?

问题描述

为了刷新我 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 和>>=运算符让我有点困惑。

这要怎么读?

标签: haskellsyntaxschememonadsinterpreter

解决方案


本质上,

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

推荐阅读