看definition of getLine
in the Haskell Prelude,
我知道递归是如何工作的,你在那里一直要求一个字符,直到你找到一个换行符,然后你建立一个列表,然后你将它包装在一个IO中。
但是我的问题是return
语句在这种情况下是如何工作的,特别是当你遇到基本情况时return (c:....:return "")
如何工作。你如何将return ""
列入名单?
答案 0 :(得分:5)
return
不是像大多数语言一样的控制结构。它是monadic值的构造函数。我们来看看它的类型:
return :: Monad m => a -> m a
在这种情况下,给定String
值,它会产生IO String
值。
return
是if
的每个分支中评估的最后一个表达式并不意味着return
结束执行的事实;其他表达式可能在return
之后发生。从列表monad中考虑这个简单的例子:
foo :: Int -> Int -> [Int]
foo x y = return x ++ return y
在monad列表中,return
只创建一个包含其参数的新单项列表。然后将这两个列表连接到函数返回的最终结果列表中。
$ return 3 :: [Int]
[3]
$ foo 3 4
[3,4]
答案 1 :(得分:0)
do
- 符号是一种语法糖。
do x <- e
rest
相当于
e >>= \x -> rest
其中>>=
是flatMap
或bind
操作(它将回调附加到IO
容器)。
flatMap :: IO a -> (a -> IO b) -> IO b
含义是:给定类型IO a
的容器附加类型为a -> IO b
的回调,当容器成功运行时触发,这会生成一个类型为{{1的新容器}}
所以
IO b
意味着什么? getLine =
getChar >>= \c ->
if c == '\n'
then (return [])
else getLine >>= \rest ->
return (c : rest)
立即将执行委托给getLine
getChar
- 容器,并带有回调,该回调分析传递给它的字符。如果是换行符,它会&#34; IO
&#34;,这是return ""
- 容器的构造,立即返回空IO
。
否则,我们会打电话给自己,抓住String
附加的rest
和return
当前c
字符。
PS:rest
用于将纯值转换为容器,因为return
接口不允许我们绑定非容器产生的回调(这有很好的理由) )。