Questions tagged [do-notation]

In Haskell, do-notation is syntactic sugar for writing monadic code, expressing computations as sequences of monadic actions. Every participant monadic value in the do block must belong to the same monad.

In Haskell, do-notation is syntactic sugar for writing monadic code expressing computations as sequences of monadic actions, each action possibly calculated -- purely -- from the preceding action's computed results.

Every participant monadic value in the same do block must belong to the same monad.

do-notation explained, in vivid colors.

do blocks translate into monadic code, but we can view this fact as implementational detail, at first. We can treat the do notation axiomatically, as an embedded language.

do blocks express sequences of monadic "actions". A simplified, standardized do-syntax is:

   do {  pattern1 <- action1
      ;  pattern2 <- action2
      ;  pattern3 <- action3
      .....................
      ;  return result
      }

Each actioni is a Haskell expression of type M ai for some monad M and some result type ai, with M the same for all is. (Examples are: Maybe a, Maybe b, Maybe c; [a], [b], [c]; IO a, IO b, IO c; etc.)

Thus each actioni "produces" its own result type ai "in" the same monad M as all the other actions in the do block.

The overall type of a do block expression is M an where an is the type of the argument result in the final return result action (which thus has the type M an). Put differently, the type of the final action in the do block is the type of the overall do block.

In particular (and a frequent cause of confusion while learning), if actioni is an if expression, each of its branches must be an expression of the same M ai type, an expression that itself could be a do block, if it needs to sequence several M actions.

Each patterni becomes match-bound to the "computed" result from the corresponding actioni, when the whole combined "computation" described by the whole do block actually "runs" (whatever that means specifically, for the specific M type). If the pattern is refutable, and the pattern match fails, the do computation chain is aborted through the invocation of M's fail method; otherwise, the computation chain continues to the next do line.

Each patterni's variable is in scope from the point of its introduction and to the end of the do block. In particular this means that the result expression in the final return result action may refer to any of the patterni's variables, as may any actionj where j > i.

It also means that the binding construct <- is non-recursive: the scope to its right (and above) contains the scope to its left (and below). That in turn means that if any variable is bound more than once, the deeper (nested) binding shadows the outer binding -- any use of a variable's name refers to its most recent binding only.

Wildcards _ can be used to ignore the computed value. If this is the case, the _ <- part can be omitted altogether.

Another special case is that by Monad laws, do { .... ; x <- action ; return x } is equivalent to do { .... ; action }.

The translation of a do code into actual monadic code goes by the rule

   do { pat <- act ; ... }
===
   act >>= f  where
           f pat = do { ... }
           f _   = fail "error-message"

and

   do { act }
===
   act

Optionally, let can also appear in a do block, which has a simple syntax re-write:

   do { actions... 
      ; let {...}          -- no "in", NB!
      ; more_actions...
      }
===
   do { actions...
      ; let {...} 
        in
          do { more_actions... }
      }
159 questions
47
votes
7 answers

Should do-notation be avoided in Haskell?

Most Haskell tutorials teach the use of do-notation for IO. I also started with the do-notation, but that makes my code look more like an imperative language more than a FP language. This week I saw a tutorial use IO with <$> stringAnalyzer <$>…
Julian.zhang
  • 709
  • 1
  • 7
  • 11
39
votes
6 answers

Using return vs. not using return in the list monad

I started my Grand Haskell Crusade (GHC :) ) and I am a bit confused with monads and IO functions. Could anyone explain simply what is the difference between those two functions? f1 = do x <- [1,2] [x, x+1] -- this is monad, right? f2 = do…
Jakub M.
  • 32,471
  • 48
  • 110
  • 179
32
votes
1 answer

Why there needs to be a $ in calls like "runSomeMonad $ do ..."?

Apparently the only possible interpretation of runSomeMonad do ... is runSomeMonad (do ...). Why isn't the first variant allowed by the Haskell syntax? Is there some case where foo do bar could be actually ambiguous?
Petr
  • 62,528
  • 13
  • 153
  • 317
28
votes
1 answer

Desugaring do-notation for Monads

As I'm learning Haskell I'm realizing that do notation is just syntatic sugar: a = do x <- [3..4] [1..2] return (x, 42) Translates into a = [3..4] >>= (\x -> [1..2] >>= (\_ -> return (x, 42))) I realize that I'll probably use…
Stephen Diehl
  • 8,271
  • 5
  • 38
  • 56
19
votes
2 answers

Is it possible to roll your own syntax sugar (like do-notation, or arrow-notation) in Haskell?

Well, the question is self-explicative. Suppose I want to implement some special syntax just for fun. Is it possible? What tools should I use?
Rafael S. Calsaverini
  • 13,582
  • 19
  • 75
  • 132
17
votes
3 answers

State Monad, sequences of random numbers and monadic code

I'm trying to grasp the State Monad and with this purpose I wanted to write a monadic code that would generate a sequence of random numbers using a Linear Congruential Generator (probably not good, but my intention is just to learn the State Monad,…
Rafael S. Calsaverini
  • 13,582
  • 19
  • 75
  • 132
16
votes
1 answer

Haskell - "How can I use "if" statement in "do" block properly?

Possible Duplicate: Haskell “do nothing” IO, or if without else Something got wrong in these "easy" lines ... action = do isdir <- doesDirectoryExist path -- check if directory exists. if(not isdir) then do…
snowmantw
  • 1,611
  • 1
  • 13
  • 25
16
votes
2 answers

How to avoid superfluous variables in do notation?

Say in a Haskell do-notation block, I wish to have a variable is_root indicating if I am root: import System.Posix.User main = do uid <- getRealUserID is_root <- return $ uid == 0 That annoying uid variable is only used in that one place. I…
ridiculous_fish
  • 17,273
  • 1
  • 54
  • 61
15
votes
1 answer

Difference between where bindings, let bindings and the single assignment operator (<-)

I do not understand the difference between the three syntaxes: where a = f (b) do a <- f (b) do let a = f (b) I do understand somehow though that a <- f(b) is different from the other two, in most cases where I tried all three worked.…
J Fritsch
  • 3,338
  • 1
  • 18
  • 40
13
votes
4 answers

Concise if-then-else notation in do-blocks in Haskell

I cannot figure out how to make the concise if-then-else notation work, mentioned at [ http://hackage.haskell.org/trac/haskell-prime/wiki/DoAndIfThenElse ]. This works, import System.Environment main = do args <- getArgs if (args !! 0) ==…
gatoatigrado
  • 16,580
  • 18
  • 81
  • 143
13
votes
2 answers

What is the type of the variable in do-notation here in Haskell?

The codes below looks quite clear: do x <- Just 3 y <- Just "!" Just (show x ++ y) Here the type of x is Num and y is String. (<- here is used to take actual value out of the Monad) However, this snippet looks not so clear to me: import…
Hanfei Sun
  • 45,281
  • 39
  • 129
  • 237
13
votes
3 answers

Haskell do notation to bind

I´am trying to desugar a do statement in Haskell. I have found some examples here on SO but wasn´t able to apply them to my case. Only thing I can think of is a heavy nested let statement, which seems quite ugly. Statement in which do notation…
floAr
  • 799
  • 1
  • 6
  • 29
12
votes
0 answers

How to implement monadic do notation using a Coroutine?

I translated the coroutine implementation from Control.Monad.Coroutine to Javascript. The translation might contain a few bugs, but my actual problem is that I don't know how to put everything together to apply it. The raw coroutine type is m…
user5536315
12
votes
2 answers

What indentation is required for a case statement within a let statement?

Working in haskell, found odd behavior, stripped it down to bare bones This Works a :: Bool a = case True of True -> True False -> False But when I try b :: IO Bool b = do let b' = case True of True -> True False ->…
user2085282
  • 1,077
  • 1
  • 8
  • 16
9
votes
1 answer

Execution order with (>>=) not what I expected

I've got a series of network requests, that each take >10 seconds. So that the user knows what's happening, I give updates: main = do putStr "Downloading the first thing... " {- Net request -} putStrLn "DONE" putStr…
amindfv
  • 8,438
  • 5
  • 36
  • 58
1
2 3
10 11