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
2
votes
2 answers

Is do notation used necessarily in the context of monad?

Haskell report 2010 says A do expression provides a more conventional syntax for monadic programming. It allows an expression such as putStr "x: " >> getLine >>= \l -> return (words l) to be written in a more traditional way as: do putStr "x: " …
Tim
  • 1
  • 141
  • 372
  • 590
2
votes
2 answers

Has the ability to use let statements in do blocks been removed in GHC 8.6.5?

I have entered some code in ghci, similar to this: main = do { a <- getLine ; let b = "Hello " ++ a ; putStrLn b } However, I get this error: :1:63: error: parse error on input `}' In previous versions of Haskell/GHC, I remember this…
schuelermine
  • 1,958
  • 2
  • 17
  • 31
2
votes
1 answer

Why can't I call a function quicksort (randomList 10)?

I have the following code: import Data.Array import Control.Monad import Data.Functor import System.Random (randomRIO) randomList 0 = return [] randomList n = do r <- randomRIO (1,6) rs <- randomList (n-1) return (r:rs) quicksort [] = [] …
Vasiliy
  • 331
  • 1
  • 12
2
votes
2 answers

Correct indentation rules using guards

I've looked at questions regarding indentation, which were of no help. My indentation also looks correct but according to the compiler it isnt. What is the correct indentation and what are the rules? readFile filename = do …
peterxz
  • 864
  • 1
  • 6
  • 23
2
votes
1 answer

How to use Control.Monad.Cont in a recursive function?

I was providing an answer to this question and an idea came to me to use Cont monad. I don't know Haskell enough to explain why this program doesn't work import Control.Monad.Cont fib1 n = runCont (slow n) id where slow 0 = return 0 slow…
Mulan
  • 129,518
  • 31
  • 228
  • 259
2
votes
3 answers

How does the operator <- in haskell behave?

I understand (somewhat) monads and understand that the operator <- will extract the value from the monad. But how does it work with different types? Typically, I have seen it being used to extract strings from IO monad. But in the example code…
peeyush singh
  • 1,337
  • 1
  • 12
  • 23
2
votes
2 answers

Haskell get values from IO domain

After reading the Haskell books I am kind of confused (or I simply forgot) how to get a value from the IO domain, into the 'Haskell world' to parse it, like so: fGetSeq = do input <- sequence [getLine, getLine, getLine] fTest input mapM_…
Madderote
  • 1,107
  • 10
  • 19
2
votes
1 answer

Can not print to file using IO Monad

Hello i have done my JSon type and i am trying to it to a file. I can do this from the prelude but i can't do it when using the IO Monad.I get the following error: Main.hs:13:24: error: * Couldn't match type `Char' with `[Char]' Expected…
Bercovici Adrian
  • 8,794
  • 17
  • 73
  • 152
2
votes
1 answer

Is it possible to check some condition before returning from a do block in Haskell?

I'm doing something like this do xs <- xss x <- x if x > 3 return x The line containing the if is giving me a compile error but I'm not really sure about the proper way to write the same thing. Just to be more clear, in Scala the equivalent…
heapOverflow
  • 1,195
  • 2
  • 15
  • 28
2
votes
2 answers

How does the List monad work in this example?

The List monad has return x = [x]. So why in the following example is the result not [(["a", "b"], [2, 3])]? > pairs a b = do { x <- a; y <- b; return (x, y)} > pairs ["a", "b"] [2,3] [("a",2),("a",3),("b",2),("b",3)]
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
2
votes
1 answer

How are expressions allowed inside Haskell do blocks

In the following code, line 4, I have an expression sandwiched between two IO actions in a do block: 1 doubleX :: (Show x, Num x) => x -> IO () …
2
votes
1 answer

What to do about 'discard' in Purescript do-notation?

Having a problem with some of the examples in the Learn Purescript by Example book. Specifically this code from section 9.3: main :: Eff (canvas :: CANVAS) Unit main = void $ unsafePartial do Just canvas <- getCanvasElementById "canvas" ctx <-…
2
votes
2 answers

Rebind do notation with typeclass-free monad

It is possible to rebind the (>>=) and return for a monad using explicit dictionary passing like this: {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RebindableSyntax #-} module Lib where import Prelude hiding ((>>=), return) data MonadDict m =…
ryskajakub
  • 6,351
  • 8
  • 45
  • 75
2
votes
2 answers

What does the put command do in a typical function using the State monad?

This is an example from https://wiki.haskell.org/All_About_Monads It's an example of using State monad to thread the StdGen value through a sequence of random numbers generating commands. If I understand what the last return does correctly it should…
Gherman
  • 6,768
  • 10
  • 48
  • 75
2
votes
2 answers

How to draw from function with arguments in Haskell?

I know that inside a do block I can draw from something monadic, "extracting" its contents. For instance, if I have a function with signature: myFunction :: MyReader (Set Int) I can do this inside a do block: mySet <- myFunction This will give me…
arussell84
  • 2,443
  • 17
  • 18