嵌套做语法

时间:2014-04-15 17:51:46

标签: haskell monads

this问题中,Will的答案会说明以下代码(我们称之为code A):

reverse2lines :: IO () 
reverse2lines = 
 do line1 <- getLine 
    line2 <- getLine
    putStrLn (reverse line2) 
    putStrLn (reverse line1)

可以转换为以下内容(让我们称之为code B):

reverse2lines = 
 do { line1 <- getLine ;
      do { line2 <- getLine ;
           do { putStrLn (reverse line2) ;
                do { putStrLn (reverse line1) } } } }

我很困惑。 我理解,例如,

addOneInt :: IO () 
addOneInt = do line <- getLine
               putStrLn (show (1 + read line :: Int))

可以转化为:

addOneInt' :: IO ()
addOneInt' = getLine >>= \line ->
             putStrLn (show ( 1 + read line :: Int))  

但我不明白嵌套do转换的工作原理。换句话说,我不明白从code Acode B的人是怎么来的?管理这种转变的规则是什么?

这些规则在何处描述/解释/指定?

有人可以通过这个(codeAcodeB)转换解释一下这里发生了什么吗?

例如,do { command1; do {command2 } }是什么意思?我该怎么解释呢?它的定义是什么?

换句话说,

之间有什么区别

do {command1;command2}

do {command1; do {command2}}

此外,

之间有什么区别

do {command1; do{command2};command3}

do {command1;do {command2; do {command3}}}

感谢阅读。

1 个答案:

答案 0 :(得分:5)

完全单独处理do表达式:嵌套它们并不会改变它们的去除方式。举个例子,我们可以从底线开始:

reverse2lines = 
 do { line1 <- getLine ;
      do { line2 <- getLine ;
           do { putStrLn (reverse line2) ;
                putStrLn (reverse line1) } } }

然后是下一个:

reverse2lines = 
 do { line1 <- getLine ;
      do { line2 <- getLine ;
           putStrLn (reverse line2) >> putStrLn (reverse line1) } }

实际上就像:

reverse2lines = 
 do { line1 <- getLine ;
      do { line2 <- getLine ;
           putStrLn (reverse line2)
           putStrLn (reverse line1) } }

然后我们可以将内部剩余的do变成一个lambda:

reverse2lines = 
 do { line1 <- getLine ;
      getLine >>= \ line2
       putStrLn (reverse line2) >>
       putStrLn (reverse line1)  }

然后,如果我们倒退,我们会发现它与以下相同:

reverse2lines = 
 do { line1 <- getLine ;
      line2 <- getLine ;
      putStrLn (reverse line2) ;
      putStrLn (reverse line1)  }

因此,正如您通过整个示例所看到的,嵌套版本与平面版本相同。事实上,如果你只看一下des do表达式的规则(我们已经看到了重要的那些),你会发现像这样嵌套它们不会改变任何东西。

事实上,这很自然,因为do的方式是递归定义的:每当我们去掉一行时,我们就会在它后面的所有行上递归,好像它们是另一行do表达