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,则不会返回空列表吗?最终结果列表的准确度如何?
在列表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)