Nie*_*and 6 haskell functional-programming
我仍在努力与Haskell,现在我遇到了一个问题,从这个例子包围我的思想输入/输出monad :
main = do
line <- getLine
if null line
then return ()
else do
putStrLn $ reverseWords line
main
reverseWords :: String -> String
reverseWords = unwords . map reverse . words
Run Code Online (Sandbox Code Playgroud)
我理解,因为像Haskell这样的函数语言不能基于函数的副作用,所以必须发明一些解决方案.在这种情况下,似乎所有东西都必须包裹在一个do块中.我得到了简单的例子,但在这种情况下我真的需要一些解释.
为什么do在I/O操作中使用一个单独的块是不够的?为什么你必须在if/else情况下打开全新的?此外,什么时候,我不知道如何调用它,domonad的"范围" 结束,即你什么时候才能使用标准的Haskell术语/函数?
该do块涉及与第一个语句相同的缩进级别的任何内容.因此,在您的示例中,它实际上只是将两个事物连接在一起:
line <- getLine
Run Code Online (Sandbox Code Playgroud)
而所有其余的,恰好相当大:
if null line
then return ()
else do
putStrLn $ reverseWords line
main
Run Code Online (Sandbox Code Playgroud)
但无论多么复杂的do语法看起来并不进入这些表达式.所以这一切都完全一样
main :: IO ()
main = do
line <- getLine
recurseMain line
Run Code Online (Sandbox Code Playgroud)
有辅助功能
recurseMain :: String -> IO ()
recurseMain line
| null line = return ()
| otherwise = do
putStrLn $ reverseWords line
main
Run Code Online (Sandbox Code Playgroud)
现在,显然这些东西recurseMain不知道函数是在domain的一个块内调用的,所以你需要使用另一个do.
do实际上并没有做任何事情,它只是简单组合语句的语法糖.一个可疑的比喻是比较do到[]:
如果您有多个表达式,可以使用:以下方法将它们组合成列表
(1 + 2) : (3 * 4) : (5 - 6) : ...
Run Code Online (Sandbox Code Playgroud)
但是,这很烦人,所以我们可以使用[]符号来编译同样的东西:
[1+2, 3*4, 5-6, ...]
Run Code Online (Sandbox Code Playgroud)
同样,如果您有多个IO语句,则可以使用>>和组合它们>>=:
(putStrLn "What's your name?") >> getLine >>= (\name -> putStrLn $ "Hi " ++ name)
Run Code Online (Sandbox Code Playgroud)
但是,这很烦人,所以我们可以使用do符号来编译同样的东西:
do
putStrLn "What's your name?"
name <- getLine
putStrLn $ "Hi " ++ name
Run Code Online (Sandbox Code Playgroud)
现在你需要多个do块的答案很简单:
如果您有多个值列表,则需要多个[]s(即使它们是嵌套的).
如果你有多个monadic语句序列,你需要多个dos(即使它们是嵌套的).