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

Do-notation and the list monad

I am learning Haskell. I am trying to find elements of a list as which sum to elements of a list bs, returning the elements as a tuple: findSum2 :: [Int] -> [Int] -> [(Int,Int,Int)] findSum2 as bs = [(a, a', b) | a <- as, a' <- as, b <- bs, a + a'…
daikonradish
  • 682
  • 5
  • 14
9
votes
1 answer

Pattern matching in do notation vs let

I recently encountered an error while using threepenny-gui and it was solved by changing the code from pattern match in the do notation with <- to pattern matching with the let notation. Is there any reasons why I should expect a change in behavior…
Davorak
  • 7,362
  • 1
  • 38
  • 48
8
votes
2 answers

Does the `do` keyword run a block or treat it as an expression?

The docs state that "The simplest way to run a block where it cannot be a stand-alone statement is by writing do before it" and provide the following example: # This dies half of the time do { say "Heads I win, tails I die."; Bool.pick } or die;…
codesections
  • 8,900
  • 16
  • 50
8
votes
3 answers

Add action without changing result to refactor do-notation

I want to sequentially compose two monad actions in Haskell, discarding any value produced by the second, and passing the argument to both actions. Currently I'm using a do-block like this: ask = do result <- getLine putStrLn result return…
amoebe
  • 4,857
  • 5
  • 37
  • 42
7
votes
2 answers

Equivalent of Haskell do-notation or F# Computation Expressions in Scala?

F# Computation Expressions allow to hide the complexity of monadic syntax behind a thick layer of syntactic sugar. Is there something similar available in Scala? I think it's for comprehensions ... Example: val f = for { a <- Future(10 / 2) // 10…
skyde
  • 2,816
  • 4
  • 34
  • 53
7
votes
2 answers

Do Notation in OCaml

Does OCaml have an equivalent to Haskell's Do Notation? Another way to put it - is there an easy way to handle nesting monadic operations more easily... cause this is annoying: open Batteries open BatResult.Infix let () = let out = …
Greg
  • 3,086
  • 3
  • 26
  • 39
7
votes
2 answers

Inconsistent do notation in functions

Why is this function allowed: -- function 1 myfunc :: String myfunc = do x <- (return True) show x and this is not: -- function 2 myfunc :: String myfunc = do x <- getLine show x The compile error: Couldn't match type `[]' with…
Gertjan Brouwer
  • 996
  • 1
  • 12
  • 35
7
votes
1 answer

LYAH - Understanding comment about "tell" when chaining Writer monads

Question is in bold at the bottom. LYAH gives this example of using the do notation with the Writer monad import Control.Monad.Writer logNumber :: Int -> Writer [String] Int logNumber x = writer (x, ["number " ++ show x]) multWithLog :: Writer…
Enlico
  • 23,259
  • 6
  • 48
  • 102
7
votes
4 answers

Guard inside 'do' block - haskell

I want to write a simple game "guess number" - with n attempts. I want to add some conditions and hits. Is it possible to use guards inside do block ? Here is my code: game = return() game n = do putStrLn "guess number: 0-99" …
tomasz pawlak
  • 151
  • 1
  • 7
7
votes
2 answers

Does the main-function in Haskell always start with main = do?

In java we always write: public static void main(String[] args){...} when we want to start writing a program. My question is, is it the same for Haskell, IE: can I always be sure to declare: main = do, when I want to write code for a program in…
August Jelemson
  • 962
  • 1
  • 10
  • 29
7
votes
4 answers

Function Composition Do Notation

Is there a "do notation" syntactic sugar for simple function composition? (i.e. (.) :: (b -> c) -> (a -> b) -> a -> c) I'd like to be able to store results of some compositions for later (while still continuing the chain. I'd rather not use the…
Chris Penner
  • 1,881
  • 11
  • 15
7
votes
2 answers

Understanding I/O monad and the use of "do" notation

I am still struggling with Haskell and now I have encountered a problem with wrapping my mind around the Input/Output monad from this example: main = do line <- getLine if null line then return () else do putStrLn $…
TheMP
  • 8,257
  • 9
  • 44
  • 73
7
votes
2 answers

Rewrite haskell list comprehension in do-notation

I have read in Learn you a Haskell, that list comprehensions in Haskell could be rewritten as monadic joins or (which is practically the same) do-notation. However, when I try to rewrite the following code (produce all possible lists having each…
sukhmel
  • 1,402
  • 16
  • 29
6
votes
3 answers

do notation and bind signature

I'm new to Haskell and functional programming and I was wondering why an example like this (the "nested loop") works: do a <- [1, 2, 3] b <- [4, 5, 6] return $ a * 10 + b Some of the stuff below is kind of pseudo-Haskell syntax, but I hope it…
jack malkovick
  • 503
  • 2
  • 14
6
votes
1 answer

Haskell - Strange do block behavior

While reading the Haskell Wikibook about MonadPlus, I found the following function which basically takes a Char and a String and returns Just (char,tail) if such char is equal the string head, or Nothing otherwise: char :: Char -> String -> Maybe…
FtheBuilder
  • 1,410
  • 12
  • 19
1
2
3
10 11