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
1
vote
1 answer

What is the difference between `let .. in do` and `<-` notation in Haskell Monads?

I'm trying to implement a function which converts a string to a list of Maybe Ints, e.g. readInts "1 2 42 foo" = [Just 1,Just 2,Just 42,Nothing]. My first aproach was: readInts (s::String) = do { ws <- words s; return (map…
1
vote
4 answers

'do' construct in Haskell

I'm trying to learn Haskell and want to write a small program which prints the content of a file to the screen. When I load it into GHCi I get the following error: The last statement in a 'do' construct must be an expression I know this question…
Anonymous Coward
  • 856
  • 1
  • 11
  • 27
1
vote
3 answers

Parse error in list monad's `do` notation

OK, so here's a weird one. This works perfectly: test = do x <- [1..5] y <- [1..5] [x+y, x-y] But this: test = do x <- [1..5] y <- [1..5] [ x+y, x-y ] fails miserably. GHC utterly refuses to parse this. No matter how I fidget…
MathematicalOrchid
  • 61,854
  • 19
  • 123
  • 220
1
vote
1 answer

Why is this a parse error in do notation?

Consider the following code: foo = do let bar = do baz bar It doesn't parse in ghc, version 8. It complains about the line containing baz. This code does parse, though: foo = do let bar = do baz bar I find this confusing. What's…
Turion
  • 5,684
  • 4
  • 26
  • 42
1
vote
1 answer

monadic desugaring haskell

Reading the chapter on monads in real world Haskell. I came across the desugaring of the do notation, specifically when we have something like pattern <- action. -- file: ch14/Do.hs doNotation3 = do pattern <- act1 act2 {- ... etc. -} …
Yusuf
  • 491
  • 2
  • 8
1
vote
1 answer

Haskell parser combinator - do notation

I was reading a tutorial regarding building a parser combinator library and i came across a method which i don't quite understand. newtype Parser a = Parser {parse :: String -> [(a,String)]} chainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser…
Yusuf
  • 491
  • 2
  • 8
1
vote
1 answer

de sugaring do notation

I want to de sugar the following do notation. But im unsure whether I have got it right: Is: quote = do time <- qtime qcomma ask <- double qcomma bid <- double qcomma askVolume <- double …
Devitect
  • 31
  • 3
1
vote
2 answers

Comparison of custom data type with parameters

I am learning Haskell and trying to implement this program. I have a custom data type data CalculatorInput = Exit | Error String | Operator (Int -> Int -> Int) | Number Int then I have a method getInput which returns a value of…
Waqar Ahmed
  • 5,005
  • 2
  • 23
  • 45
1
vote
2 answers

Sequencing basic parsers in Haskell and Frege using do notation

I try to run snippets from chapter 8 about functional parsers in Graham Hutton's 'Programming in Haskell' both in ghci and frege-repl. I'm not able to sequence parsers using do syntax. I have following definitions in Frege (Haskell version differs…
libnull-dev
  • 881
  • 1
  • 7
  • 19
1
vote
3 answers

Store result of function applications in a tuple inside a DO-block

While I can apply a function two times and bind result in a tuple: let foo :: Num a => a -> a foo x = x + 1 let (x,y) = (foo 10, foo 20) This can't be done (ar at least I don't know how to do it properly) within a do block: let bar…
gsscoder
  • 3,088
  • 4
  • 33
  • 49
1
vote
1 answer

understanding do notation and bindings

I am very new to haskell and I am trying to understand the methodology used to create Monadic parser in this document https://www.cs.nott.ac.uk/~gmh/pearl.pdf Instead of following it exactly, I am trying to do it a little bit differently in order to…
yasar
  • 13,158
  • 28
  • 95
  • 160
1
vote
1 answer

Is it true that order of execution inside a do block doesn't depend on the statement order?

I was reading https://wiki.haskell.org/Do_notation_considered_harmful and was surprised to read the following lines Newcomers might think that the order of statements determines the order of execution. ... The order of statements is also not the…
XrXr
  • 2,027
  • 1
  • 14
  • 20
1
vote
1 answer

If/then/else in do statements (Haskell)

I've got a block of code that I've written which doesn't compile because the if/then/else block isn't set out in a way the compiler understands, however I can't figure out how to rewrite it so that it can. playRandomly board = do …
Harvey Adcock
  • 929
  • 1
  • 7
  • 16
1
vote
1 answer

How to correctly discard result of a (monadic) computation in F#

In Haskell, I can write: token: Parser a -> Parser a token p = do space v <- p space return v In F#, I have come this far: let token = compose { let! _ = space let! v = parser let! _…
Paul Kapustin
  • 3,297
  • 5
  • 35
  • 45
0
votes
1 answer

Can I always replace do ... pure ... with ado ... in ... in Purescript?

Can I always replace a do-block like this: do ... pure ... where the last line is "pure" something, with an ado-block like this: ado ... in ... ? I know do only requires Bind and not Monad (i.e. Applicative), but we're already using pure…
Filip Haglund
  • 13,919
  • 13
  • 64
  • 113