在本教程http://learnyouahaskell.com/starting-out中,作者编写了这段代码。
boomBangs xs = [ if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x]
然后像这样执行它
boomBangs[7..13]
我的问题是,“ <-”运算符的作用是什么?在我看来,这似乎会导致递归行为,因为我是在参照函数中看起来像我的东西,或者定义如何创建列表推导。
四处搜寻,我在另一个question上找到了chi的解释:
“ x <-操作运行IO操作,获取其结果,并将其绑定到x”
上面链接的问题中的“ <-”与我上面复制的代码中使用的“ <-”是否不同? xs是否在xs内运行?如果有人可以向我解释一下这里发生的一切,我将不胜感激。
答案 0 :(得分:1)
您的列表理解实质上是以下方面的语法糖:
import Control.Monad(guard)
boomBangs :: Integral i => [i] -> [String]
boomBangs xs = do
x <- xs
guard (odd x)
return (if x < 10 then "BOOM!" else "BANG!")
因此,这是do
expression [Haskell report],正如报告所说,它是语法糖。它是用于以下方面的语法糖:
boomBangs xs = xs >>= \x -> (guard (odd x) >> return (if x < 10 then "BOOM!" else "BANG!"))
对于列表,Monad
实例定义为:
instance Monad [] where
(>>=) = flip concatMap
return x = [x]
此外,guard
定义为:
guard :: Monad m => Bool -> m ()
guard True = pure ()
guard False = empty
,(>>)
的默认实现是:
(>>) :: Monad m => m a -> m b -> m b
(>>) u v = u >>= \_ -> v
因此boomBangs
基本上实现为:
boomBangs xs = concatMap (\x -> (guard (odd x) >>= \_ -> [if x < 10 then "BOOM!" else "BANG!"])) xs
= concatMap (\x -> concatMap (\_ -> [if x < 10 then "BOOM!" else "BANG!"]) guard (odd x)) xs
自列表以来,guard
可以专门用于:
-- guard for the Monad []
guard :: Bool -> [()]
guard True = [()]
guard False = []
因此,这意味着如果guard
得到一个True
,它将返回一个单例列表,而对于False
将返回一个空列表。因此,这意味着给定防护措施,concatMap (\_ -> [if x < 10 then "BOOM!" else "BANG!"])
将返回[if x < 10 then "BOOM!" else "BANG!"]
中的内容,如果防护措施失败,它将返回一个空列表。因此,警卫队充当某种过滤器。
那么x <-
是什么。如果我们看一下do
表达式是如何删除的,则x <- foo
对应于foo >>= \x -> ...
。
对于列表理解,x <- ...
充当某种“枚举器”:它将枚举列表中的所有元素,而x
每次将获得列表中的一个元素以进行操作进一步处理。