Nested do syntax

匿名 (未验证) 提交于 2019-12-03 01:22:02

问题:

In this question Will's answer states that the following code (let's call it code A):

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

can be transformed into the following (let's call it code B) :

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

I am confused. I understand, for example, that

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

can be transformed into:

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

But I don't understand how the nested do transformation works. In other words, I don't understand how one arrives from code A to code B ? What are the rules governing this transformation ?

Where are these rules described / explained / specified ?

Could someone please explain what is going on here with this (codeA to codeB) transformation ?

For example, what does do { command1; do {command2 } } mean ? How should I interpret that ? What is its definition ?

In other words,

what is the difference between

do {command1;command2} and

do {command1; do {command2}} ?

Furthermore, what is the difference between

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

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

Thanks for reading.

回答1:

Just treat the do expressions completely separately: nesting them does not change how they get desugared. For your to example, we can start with the bottom line:

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

then the next one:

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

which is, in fact, just like:

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

then we can turn the inner remaining do into a lambda:

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

And then, if we go backwards, we see that it's the same as just:

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

So, as you can see by going through the whole example, the nested version is the same as the flat version. In fact, if you just look at the rules for desugaring do expressions (and we've seen the important ones), you'll see that nesting them like this does not change anything.

In fact, this is pretty natural because the way do is desugared is defined recursively: each time we desugar a single line, we recurse on all the lines following it as if they were another do expression.



转载请标明出处:Nested do syntax
文章来源: Nested do syntax
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!