Do notation is Haskell syntax for building one larger action from smaller monadic actions. A `do` block runs actions in written order, lets later steps use earlier results, and keeps interaction with the environment inside an `IO` action rather than a pure function. section 3.1.1 section 3.5
Read and echo a line
`<-` evaluates an action at that point and binds its produced value. Here `getLine` produces a `String`, which `putStrLn` consumes; the final statement gives the whole block type `IO ()`. `main = do` ` line <- getLine` ` putStrLn line` section 3.1.1
A line without `<-` sequences an action whose result is not needed. Use `_ <-` when deliberately discarding a result. `return` wraps a value in an action; it does not exit the block. Because the final expression determines an action's result, conditional branches inside an `IO` block must both produce compatible IO actions. section 3.1.3 section 3.5
Loop until empty input
A recursive action can read input, stop with `return ()`, or create a nested `do` block to perform several actions before recurring. `interactiveLines counter = do` ` line <- getLine` ` if null line` ` then return ()` ` else do` ` putStrLn (show counter ++ ". " ++ line)` ` interactiveLines (counter + 1)` section 3.1.3
Do notation applies beyond `IO`: it is syntactic sugar for monadic bind. `do x <- m; f x` corresponds to `m >>= f`, while `do _ <- m1; m2` corresponds to `m1 >> m2`. In parsers, this makes dependencies between parsed values explicit; failure in an earlier parser short-circuits the remaining work. section 12.1.5 section 12.1.5
do x <- m f x
Compare a single binding written with `>>=` and with `do` notation. section 12.1.5

