“<-”是什么意思?
What does "<-" mean?
本教程http://learnyouahaskell.com/starting-out作者写了这段代码
boomBangs xs = [ if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x]
然后再这样执行
boomBangs[7..13]
我的问题是,“<-”运算符的作用是什么?在我看来,这似乎会导致递归行为,因为我引用的是在我看来像是函数内部的函数,或者可能定义了如何创建列表理解。
四处搜索,我在另一个 :
上找到了 chi 的解释
"x <- action runs the IO action, gets its result, and binds it to x"
上面链接的问题中的“<-”与我上面复制的代码中使用的“<-”不同吗? xs 运行 是否在 xs 内部?如果有人能向我解释这里发生了什么,我将不胜感激。
你的列表理解本质上只是语法糖:
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
,它 return 是一个单例列表,而 False
是一个空列表。这意味着如果守卫持有,concatMap (\_ -> [if x < 10 then "BOOM!" else "BANG!"])
将 return [if x < 10 then "BOOM!" else "BANG!"]
中的内容,如果守卫失败,它将 return 一个空列表。因此,守卫充当某种过滤器。
那么现在x <-
是什么。如果我们看一下 do
表达式是如何脱糖的,x <- foo
对应于 foo >>= \x -> ...
.
对于列表理解,x <- ...
充当某种 "enumerator":它将枚举列表中的所有元素,并且 x
每次都会获取其中一个元素待进一步处理的列表。
本教程http://learnyouahaskell.com/starting-out作者写了这段代码
boomBangs xs = [ if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x]
然后再这样执行
boomBangs[7..13]
我的问题是,“<-”运算符的作用是什么?在我看来,这似乎会导致递归行为,因为我引用的是在我看来像是函数内部的函数,或者可能定义了如何创建列表理解。
四处搜索,我在另一个
上找到了 chi 的解释
"x <- action runs the IO action, gets its result, and binds it to x"
上面链接的问题中的“<-”与我上面复制的代码中使用的“<-”不同吗? xs 运行 是否在 xs 内部?如果有人能向我解释这里发生了什么,我将不胜感激。
你的列表理解本质上只是语法糖:
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
,它 return 是一个单例列表,而 False
是一个空列表。这意味着如果守卫持有,concatMap (\_ -> [if x < 10 then "BOOM!" else "BANG!"])
将 return [if x < 10 then "BOOM!" else "BANG!"]
中的内容,如果守卫失败,它将 return 一个空列表。因此,守卫充当某种过滤器。
那么现在x <-
是什么。如果我们看一下 do
表达式是如何脱糖的,x <- foo
对应于 foo >>= \x -> ...
.
对于列表理解,x <- ...
充当某种 "enumerator":它将枚举列表中的所有元素,并且 x
每次都会获取其中一个元素待进一步处理的列表。