3

我正在guard从“Learn You a Haskell for Great Good!”一书中了解该功能。米兰利波卡。

对于以下示例:

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

我知道这guard需要一个布尔值,如果该值为True,则 guard()将其放入最小的默认上下文中并成功。如果值为False,则guard生成失败的一元值。

但是,我不明白在上面的示例中,guard 是如何创建结果列表的[7, 17, 27, 37, 47]x在 lambda 函数中传递了什么,是 1 吗?此外,如果('7' `elem` show x)计算结果为False,那么不会返回空列表吗?最终的结果列表到底是怎么来的?

4

1 回答 1

6

在列表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 个元素的列表作为中间值,每个元素都是一个列表,如果其字符串表示形式包含 digit 7,则它是输入值的单例列表,否则为空列表:

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

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

什么在 lambda 函数中作为 x 传递,是 1 吗?

它是输入列表的每个元素,1通过50.

如果条件为真,则内部concatMap产生,如果条件为假,因为如果条件为真,则产生一个元素的列表( dummy ),如果条件为假,则产生一个空列表 - 如果您将其改写为等价物:[x][]guard()

map (\_ -> x) (if '7' `elem` show x then [()] else [])
-- or
if '7' `elem` show x then [x] else []
于 2019-08-05T01:02:52.613 回答