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
6
votes
1 answer

Refactoring a Haskell function that uses the Reader monad

I've got some code that looks sort of like this, ignoring all the code that isn't relevant to my question: import qualified Control.Monad.Reader as Reader data FooEnv = FooEnv { bar :: Int -> Int } type FooReader = Reader.Reader FooEnv foo :: Int…
arussell84
  • 2,443
  • 17
  • 18
6
votes
2 answers

Expressing do block using only monadic bind syntax

As far as I know, do blocks in Haskell are just some kind of syntactic sugar for monadic bind operators. For example, one could convert main = do f <- readFile "foo.txt" print f print "Finished" to main = readFile "foo.txt" >>=…
Uli Köhler
  • 13,012
  • 16
  • 70
  • 120
6
votes
2 answers

returning an element extracted from a monad; redundant?

Are the following two implementations of flatten equivalent for all well-behaved Monads? flatten1 xss = do xs <- xss x <- xs return x flatten2 xss = do xs <- xss xs
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
5
votes
1 answer

Making QualifiedDo and ApplicativeDo work together when nesting applicative functors

I want to define deeply nested compositions of applicative functors. For example something like this: {-# LANGUAGE TypeOperators #-} import Control.Monad.Trans.Cont import Control.Arrow (Kleisli (..)) import Data.Aeson import Data.Aeson.Types import…
danidiaz
  • 26,936
  • 4
  • 45
  • 95
5
votes
3 answers

Haskell IF Else

input <- readLn if (input == 0) then putStr "0" else if (input ==1) then putStr "1" else if (input ==2) in this kind of senario how to use multiple putStr with in a then or else if ? when i try getting a error Type error in…
Sudantha
  • 15,684
  • 43
  • 105
  • 161
5
votes
1 answer

How to use variable from do block assignment line in a where clause?

I have the following sample of code: {-# LANGUAGE ScopedTypeVariables #-} main = do putStrLn "Please input a number a: " a :: Int <- readLn print a putStrLn "Please input a number b: " b :: Int <- readLn print b putStrLn…
altern
  • 5,829
  • 5
  • 44
  • 72
5
votes
2 answers

Why does a "let" statement force an "applicative do" block into requiring a monad constraint?

Consider this example: {-# language ApplicativeDo #-} module X where data Tuple a b = Tuple a b deriving Show instance Functor (Tuple a) where fmap f (Tuple x y) = Tuple x (f y) instance Foldable (Tuple a) where foldr f z (Tuple _ y) = f…
Ignat Insarov
  • 4,660
  • 18
  • 37
5
votes
2 answers

How do I conditionally bind in a do block?

I want to achieve the following in a do block: do if condition then n0 <- expr0 else n0 <- expr0' n1 <- expr1 n2 <- expr2 return T n0 n1 n2 But Haskell gives a compile error unless I do: do if condition then n0 <- expr0 …
sinoTrinity
  • 1,125
  • 2
  • 15
  • 27
5
votes
3 answers

Generating a unique value in Haskell do-notation

To generate x86 assembly code, I have defined a custom type called X86: data X86 a = X86 { code :: String, counter :: Integer, value :: (X86 a -> a) } This type is used in do-notation like the following. This makes it easy to write templates for…
Ryan
  • 2,378
  • 1
  • 19
  • 29
5
votes
1 answer

Monadic do notation inside let, is it possible?

Consider the following valid Haskell code module Main where main :: IO () main = do let x = f print x f :: Maybe (Int, Int) f = Just 3 >>= (\a -> Just 5 >>= (\b -> return (a, b))) where the function f can be rewritten equivalently…
ruben.moor
  • 1,876
  • 15
  • 27
5
votes
1 answer

Why should fail method exist in the monad type class?

So I have this line of code: [Nothing] >>= \(Just x) -> [x] which of course gives exception, because the pattern doesn't match Nothing. On the other hand, this code gives a different result, []: do Just x <- [Nothing] return x As I see it,…
Brrch
  • 331
  • 1
  • 4
5
votes
3 answers

Can you turn a Haskell list into a series of do instructions?

Can you create a list of functions and then execute them sequentially, perhaps passing them into do notation? I'm currently doing this by mapping over a list of data and am wondering if I can call somehow pass the result as a series of sequential…
toofarsideways
  • 3,956
  • 2
  • 31
  • 51
5
votes
1 answer

How does this getRight :: Either a b -> Maybe b work?

At HaskellWiki's Do notation considered harmful, section Useful applications, I found: It shall be mentioned that the do sometimes takes the burden from you to write boring things. E.g. in getRight :: Either a b -> Maybe b getRight y = do…
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
4
votes
3 answers

How does Haskell "desugar" getline in this do block?

I've read a few books on Haskell but haven't coded in it all that much, and I'm a little confused as to what Haskell is doing in a certain case. Let's say I'm using getLine so the user can push a key to continue, but I don't really want to interpret…
noisebloom
  • 65
  • 5
4
votes
1 answer

Is there a better way to mimic do notation in JS?

Monadic computations quickly become confusing in JS: const chain = fm => xs => xs.reduce((acc, x) => acc.concat(fm(x)), []); const of = x => [x]; const main = xs => ys => zs => chain(x => x === 0 ? [] : chain(y => …
user5536315
1 2
3
10 11