了解守卫功能和列表理解

Understanding the guard function and list comprehension

我正在从 Miran Lipovaca 的书 'Learn You a Haskell for Great Good!' 中学习 guard 函数。

对于以下示例:

ghci> [1..50] >>= (\x -> guard('7' `elem` show x) >> return x)
[7, 17, 27, 37, 47]

我知道guard取一个布尔值,如果取值为True,guard取()放到一个最小的默认上下文中就成功了。 如果值为 False,则 guard 会产生一个失败的 monadic 值。

但是,我不明白上面例子中的 guard 如何工作来创建结果列表 [7, 17, 27, 37, 47]。在 lambda 函数中作为 x 传递的是什么,是 1 吗?此外,如果 ('7' `elem` show x) 的计算结果为 False,那么不会返回空列表吗?最终的成绩单究竟是如何得出的?

在列表Monad实例中:

  • >>=concatMap,参数翻转后

  • guard condition 等同于 if condition then [()] else []

并且在任何 Monad 实例中,a >> b = a >>= \_ -> b,因此在列表实例中这等同于 concatMap (\_ -> b) a.

因此您的代码脱糖为:

concatMap
  (\x -> concatMap
    (\_ -> [x])
    (if '7' `elem` show x then [()] else []))
  [1..50]

因此外部 concatMap 生成一个包含 50 个元素的列表作为中间值,每个元素都是一个列表,如果其字符串表示形式包含数字 7,则它是输入值的单例列表,或者空列表:

[[], [], [], [], [], [], [7], [], [], [], [], [], [], [], [], [], [17], …]

然后将其连接起来产生最终结果 [7, 17, 27, 37, 47]

What is passed as x in the lambda function, is it 1?

它是输入列表的每个元素,150

如果条件为真,内部 concatMap 生成 [x],如果条件为假,则生成 [],因为 guard 生成一个元素列表(虚拟()) 如果条件为真,如果条件为假则为空列表——如果将其改写为等价物,这可能更容易理解:

map (\_ -> x) (if '7' `elem` show x then [()] else [])
-- or
if '7' `elem` show x then [x] else []