我正在从“学到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
,那么是否不返回空列表?最终结果列表将如何显示?
答案 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吗?
它是输入列表1
至50
的每个元素。
如果条件为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 []