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

how exactly do expression makes the list comprehension redundant haskell

We know that list comprehensions and do expressions are equivalent for lists. Also list comprehensions are redundant. But can someone explain how exactly do notation makes the list comprehension redundant? Is there some difference with filtering?
xmathx
  • 31
  • 2
0
votes
1 answer

Haskell : non-symmetric nested do-notation and let

I'm learning Haskell through writing toy-language. And I wondering how combine let with nested-do constraction. I want to write something like that (completely usual use-case but with State-monad in do-notation): let x' = if special x then do ...…
0
votes
2 answers

How are state monads / monad transformers desugared inside do notation?

Example sumArray :: Array Int -> State Int Unit sumArray = traverse_ \n -> modify \sum -> sum + n t1 :: Int t1 = execState (do sumArray [1, 2, 3] sumArray [4, 5] sumArray [6]) 0 -- returns 21 module Main where import Prelude import Effect…
0
votes
1 answer

Understanding Haskell (<-) syntactic sugar

I'm trying to parse a CSV file using Cassava. I want a function that returns Nothing if parse was unsuccessful and Just (V.Vector (String, String, String)) otherwise. I'm using the code below: {-# LANGUAGE ScopedTypeVariables #-} module Lib (…
testin3r
  • 121
  • 1
  • 9
0
votes
4 answers

How to quickly read the do notation without translating to >>= compositions?

This question is related to this post: Understanding do notation for simple Reader monad: a <- (*2), b <- (+10), return (a+b) I don't care if a language is hard to understand if it promises to solve some problems that easy to understand languages…
PPP
  • 1,279
  • 1
  • 28
  • 71
0
votes
1 answer

Haskell: arrows on trees, XML, and Hxt: Transform text leaves into subtrees

Background The Freeplane app seems to have died its decades-long death. I'm extracting my data from it. Freeplane stores data as XML. One of the first steps I'm taking is to homogenize that format. Question, and what I wanted to do My goal is to…
Jeffrey Benjamin Brown
  • 3,427
  • 2
  • 28
  • 40
0
votes
1 answer

"Couldn't match type ‘[]’ with ‘IO’" error in Haskell

I am trying to make a list with Points (a datatype that I created), the idea is add an element in each iteration. Something is wrong. I have tried to put p out of myLoop but it doesn't seems to work either. main = myLoop myLoop = do …
0
votes
1 answer

How does `return` statement have different type than that of a function's definition?

Within a loop, integers are collected inside a list, and a tuple of these integers is returned. How does this change to a list of tuples? input :: IO [(Int,Int)] input = do n <- readLn :: IO Int forM [1..n] $ \_ -> do [x,y] <- map read .…
Ndosho Mbwana
  • 31
  • 1
  • 1
  • 5
0
votes
1 answer

Haskell How to compare IO tuple with normal tuple

I try to compare the tuple members (date) of an IO tuple with a normal tuple. d1 ->(Integer, Int, Int) and d2 -> IO (Integer, Int, Int), Is it possible to compare these two tuples? I've tried something like that: import Data.Time.Clock import…
Habebit
  • 957
  • 6
  • 23
0
votes
2 answers

if statement in do block gives error message

I'm trying to make a very simple snake-like game where, if you try to go to a x,y coordinate you have already visited, you lose the game. This is code that's working so far (you can move player 1 with arrowkeys and player 2 with wasd): import…
abc556
  • 37
  • 5
0
votes
1 answer

What is the Big-O of the function n^2/log(n)?

the time complexity of an algorithm is given by n^2/log(n). what is that in big O notation? Just n^2 or we keep the log?
DAVID
  • 21
  • 2
0
votes
2 answers

Could pattern-matching in do-notation/enumFromTo slow down a Haskell code?

I've been solving a pretty easy problem: generation of all decreasing sequences in length of L, consisting of natural numbers from 1 up to M in lexicographical order. Yet, I ran into a quite strange issue. Take a look: c :: (Ord a, Num a, Enum a) =>…
Zhiltsoff Igor
  • 1,812
  • 8
  • 24
0
votes
2 answers

How to rewrite `do` block using bind with an IO read Int?

So, I want to rewrite the given prog function with using >>/>>= bindings instead of do and <- : prog :: IO Int prog = do putStrLn "Hello there! How old are you?" age <- (readLn :: IO Int) let agedays = show $ age * 365 …
ArdianH101
  • 55
  • 5
0
votes
4 answers

Do statement under a where clause

I'm trying to convert IO [String] to [String] with <- binding; however, I need to use a do block to do that under a where statement, but Haskell complains about the indentation all the time. Here is the code: decompEventBlocks :: IO [String] -> IO…
Our
  • 986
  • 12
  • 22
0
votes
3 answers

Can we access the output from a replicateM defined in a do-block

Assume i have something like this main = do input_line <- getLine let n = read input_line :: Int replicateM n $ do input_line <- getLine let x = read input_line :: Int return () ***putStrLn $ show -- Can i…
JohEker
  • 627
  • 5
  • 13
1 2 3
10
11