了解保护功能和列表理解

时间:2019-08-05 00:24:28

标签: list haskell list-comprehension monads guard-statement

我正在从“学到Haskell为伟大的事物!”一书中学习guard函数。由Miran Lipovaca撰写。

对于以下示例:

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]。在lambda函数中作为x传递的是1吗?此外,如果('7' `elem` show x)的值为False,那么是否不返回空列表?最终结果列表将如何显示?

1 个答案:

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

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

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

  

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

它是输入列表150每个元素。

如果条件为true,则内部concatMap会生成[x],如果条件为false,则内部[]会生成guard,因为()会生成一个元素列表(伪{ 1}}),如果条件为true,则为空列表,如果条件为false,则将其重新表述为等效项可能更容易:

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