如何不使用flipType定义《Haskell从First Principles》第18章习题5的meh函数?
问题与解答:不依赖flipType逻辑实现meh函数
我懂你现在的困扰——之前写的meh用了自己实现的concatMonads,但这个函数的功能和后面要做的flipType几乎一模一样,完全绕开了练习想要的递进逻辑。其实我们可以直接从Monad的核心操作出发,用递归遍历列表的方式来实现meh,完全不用提前拼接一堆m b值。
正确的实现思路
不用先把整个列表转成[m b]再处理,而是直接逐个处理列表元素:
- 遇到空列表,直接返回一个包含空列表的Monad值(
pure []) - 遇到非空列表,先把第一个元素通过
transform转成m b,然后用Monad的绑定操作(>>=),把这个值和剩余列表的meh结果结合,把当前的b放到结果列表的最前面。
代码实现(基础版)
meh :: Monad m => [a] -> (a -> m b) -> m [b] meh [] _ = pure [] meh (x:xs) transform = transform x >>= \currentB -> meh xs transform >>= \remainingBs -> pure (currentB : remainingBs)
用do notation简化(更易读)
如果觉得嵌套的>>=看着头疼,用Haskell的do语法糖可以让代码更清晰:
meh :: Monad m => [a] -> (a -> m b) -> m [b] meh [] _ = pure [] meh (x:xs) transform = do currentB <- transform x remainingBs <- meh xs transform pure (currentB : remainingBs)
为什么这样符合要求?
这个实现完全没有先把列表转换成[m b]再拼接的步骤,而是从头开始用Monad的绑定操作逐步构建最终的m [b]值,完美避开了类似flipType的逻辑。这样后续就可以按照题目要求,轻松用meh实现flipType:
flipType :: Monad m => [m b] -> m [b] flipType l = meh l id
这样整个练习的递进逻辑就通顺了——先实现处理列表+转换函数的meh,再复用它实现把[m b]转成m [b]的flipType。
内容的提问来源于stack exchange,提问作者Eponymous
相关产品推荐
相关产品推荐

