了解保护功能和列表理解

cen*_*980 3 monads haskell list-comprehension list guard-statement

我正在guard从“学习Haskell带来的好处!”一书中学习该功能。由Miran Lipovaca撰写。

对于以下示例:

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

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

但是,我不明白在上面的示例中guard是如何工作的,以创建结果列表[7, 17, 27, 37, 47]x在lambda函数中传递的是1吗?此外,如果('7' `elem` show x)计算结果为False,则不会返回空列表吗?最终结果列表的准确度如何?

Jon*_*rdy 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]
Run Code Online (Sandbox Code Playgroud)

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

[[], [], [], [], [], [], [7], [], [], [], [], [], [], [], [], [], [17], …]
Run Code Online (Sandbox Code Playgroud)

然后将其串联以产生最终结果[7, 17, 27, 37, 47]

在lambda函数中作为x传递的是1?

它是输入列表中每个元素(1通过)50

concatMap产生[x],如果条件为真,[]如果条件是假的,因为guard会产生一个元素(虚拟列表())如果条件为真,如果它是一个空列表的假,这可能是更容易地看到,如果你改写它作为等价物:

map (\_ -> x) (if '7' `elem` show x then [()] else [])
-- or
if '7' `elem` show x then [x] else []
Run Code Online (Sandbox Code Playgroud)