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

How to randomly shuffle a list

I have random number generator rand :: Int -> Int -> IO Int rand low high = getStdRandom (randomR (low,high)) and a helper function to remove an element from a list removeItem _ [] = [] removeItem x (y:ys) | x == y = removeItem…
Tomer
  • 1,159
  • 7
  • 15
1
vote
1 answer

Fighting IO when reading a configuration file into Haskell

I have input data intended for my yet-to-be-written Haskell applications, which reside in a file. I don't update the file. I just need to read the file and feed it into my Haskell function which expects a list of strings. But reading the file of…
user1934428
  • 19,864
  • 7
  • 42
  • 87
1
vote
1 answer

concatenate getLine input with haskell array throws a type error

im totally beginner at Haskell i came from js environment , i have a simple array students into which i want to push some student objects but sadly Haskell does not support objects ( if there is a way i can do it please guide me ) so tried to make a…
1
vote
2 answers

type tetris - stuck mixing monadic and pure code

I'm trying to implement bits and pieces of vulkan-tutorial in haskell. For now im stuck trying to translate this code from c: for (const char* layerName : validationLayers) { bool layerFound = false; for (const auto& layerProperties :…
Pavel Beliy
  • 494
  • 1
  • 3
  • 14
1
vote
2 answers

Haskell IO : Printing Command Line Arguments

I have this program which just prints out the command line arguments. echoArgs :: IO () echoArgs = do line <- getArgs print line What I wanted to know is that why does this fail when I type: echoArgs :: IO () echoArgs = do …
Rahat
  • 305
  • 1
  • 4
  • 10
1
vote
2 answers

Is there a way of receiving IO outside of main in Haskell?

It may be a dumb question but I got an error when I try to get an input outside of the main function: menu2Players :: String -> String -> (String, String) menu2Players player1 player2 = do putStrLn("Qual o nome do primeiro jogador?\n") …
Some
  • 21
  • 3
1
vote
3 answers

Random grid of elements using Haskell

Having absolutely zero experience with Haskell, I need to come up with a code equivalent to this Python one: from random import choice, sample def random_subset(): return tuple(sample(('N', 'S', 'W', 'E'), choice((1, 2, 3, 4)))) def…
Enirsa
  • 85
  • 1
  • 7
1
vote
1 answer

Why this dictionary function is not working

I am trying to create and use a dictionary with code from here: import Data.List (lookup) insert :: Eq a => (a,b) -> [(a,b)] -> [(a,b)] insert (a,b) [] = [(a,b)] insert (a,b) ((c,d):rest) = if a == c then (a,b) : rest else (c,d)…
rnso
  • 23,686
  • 25
  • 112
  • 234
1
vote
2 answers

fmap into a do block fails with a print error

I'm trying to understand why a function I have written with a do-block can't be rewritten to fmap a similar lambda expression over a list. I have the following: -- This works test1 x = do let m = T.pack $ show x T.putStrLn m test1…
Mittenchops
  • 18,633
  • 33
  • 128
  • 246
1
vote
1 answer

Can I have separate functions for reading and writing to a txt file in Haskell, without using a 'main' function?

I'm making a program using Haskell that requires simple save and load functions. When I call the save function, I need to put a string into a text file. When I call load, I need to pull the string out of the text file. I'm aware of the complexities…
SuperHanz98
  • 2,090
  • 2
  • 16
  • 33
1
vote
2 answers

Question about the Writer monad as taught in LYAH. (How did the appending to the log take place?)

I'm learning Haskell from the "Learn you a Haskell for Great Good" tutorial and I've got to the part on writer monads. Here's the example that I can't figure out. import Control.Monad.Writer logNumber :: Int -> Writer [String] Int logNumber x =…
Andy
  • 11
  • 2
1
vote
2 answers

Ask user for list input in Haskell

I found this code online, but it's not running. main = do xs <- getLine [] print xs So how do I ask the user for list input in Haskell? I am new to Haskell, please explain when you answer. Thanks.
user11239824
1
vote
2 answers

A mystery involving putStrLn

Why does the piece of code below produce the error parse error on input ‘putStrLn’? main = do line <- fmap reverse getLine putStrLn $ "You said " ++ line ++ " backwards!" putStrLn $ "Yes, you said " ++ line ++ "…
user65526
  • 685
  • 6
  • 19
1
vote
2 answers

Haskell recursion in IO action

Still a beginner that can't figure out a recursive loop in an IO action. Assume: fMinInspect :: Int fMinInspect = 1 fMaxInspect :: Int fMaxInspect = 12 -- fNoInspectPerHour :: IO () fNoInspectPerHour = do generateInspect <- randomRIO…
Madderote
  • 1,107
  • 10
  • 19
1
vote
2 answers

Is it possible write this code without using do notation?

I have some function bar :: MyType -> MyType -> [MyType] I would like to have another function: foo :: [MyType] -> [MyType] foo xs = do x <- xs y <- xs bar x y Is it possible to write foo without using the do notation? I…
user1747134
  • 2,374
  • 1
  • 19
  • 26