jhegedus
jhegedus

Reputation: 20653

Simple example on do syntax transformed to >>= syntax

How can reverse2lines transformed into the using >>= syntax ? Just like addOneInt is transformed into addOneInt'?

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


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

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

Please also consider reading the follow up question and its valuable answers.

Upvotes: 1

Views: 209

Answers (3)

jhegedus
jhegedus

Reputation: 20653

Here is the code from Will's very nice answer using only >>= :

reverse2lines' :: IO () 
reverse2lines' = 
    getLine >>= (\line1 -> 
        getLine >>= (\line2 -> 
            putStrLn (reverse line2) >>= (\_ ->
               putStrLn (reverse line1) )))

Lesson learned : the sequencing in do corresponds simply to nesting of lambda expressions.

Upvotes: 1

Will Ness
Will Ness

Reputation: 71119

You could safely deduce it from what you already know. Start by fully parenthesizing your addOneInt':

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

Next, you reverse2lines can be equivalently written as

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

Applying the one-step transformation that you already used for addOneInt, as much times as needed, you'd get

reverse2lines' :: IO ()
reverse2lines' = 
    getLine  >>=  (\line1 ->
      getLine  >>=  (\line2 ->
        putStrLn (reverse line2)  >>
          putStrLn (reverse line1) ) )

Syntactically, the parentheses around lambda expressions can be omitted, but writing them explicitly here helps to clarify and make obvious the nested structure of these functions, especially if we'd line up the indentation.

Full translation arranges for the monad's fail function to be called on pattern mismatch, but since the variable patterns (line1, line2) are irrefutable, this translation is in fact exact.

Upvotes: 5

Benesh
Benesh

Reputation: 3428

Statements of type x <- m can be translated as m >>= \x -> ..., and statements in which the return value isn't bound like m can be translated as m >> ...

reverse2lines :: IO () 
reverse2lines = getLine 
                >>= \line1 -> getLine 
                >>= \line2 -> putStrLn (reverse line2)
                >> putStrLn (reverse line1)

The translation isn't exact - the fail monad function complicates things a little. You can read about it here, but as far as I know it's irrelevant when dealing with the IO monad.

Upvotes: 4

Related Questions