2

I wrote some monadic code using a reader monad and I wonder if there is any way to write using the do-notation:

m = Map.fromList [("This","is"), ("is","the"), ("the","secret")]
f x m = fromMaybe "default" $ Map.lookup x m

r :: String -> Reader (Map String String) String)
r x = reader $ \m1 -> f x m1

runReader ((r "This") >>= r >>= r) m
-- "secret"

Now how would you write the last statement in do notation.

I have a feeling all the "expanded monads" using runX functions don't really lend to do-notation.

hgiesel
  • 5,430
  • 2
  • 29
  • 56
  • 3
    `runReader (do { s1 <- r "This"; s2 <- r s1; r s2 }) m` does it. Although for this sort of stuff, you are probably more interested in the `>=>` operator and `Kleisli` newtype. For example, `runReader ((r >=> r >=> r) "This") m` does the same thing. – Alec Jun 26 '17 at 23:59

2 Answers2

3

You could do

runReader threeRs m where
  threeRs = do
   a <- r "This"
   b <- r a
   r b

although I would not recommend this. In this case using the bind (>>=) operator fits the actual chaining quite well.

IMHO do notation is most useful when sequencing monadic operations where not all results are needed, results should be combined, or pure functions are used inbetween. See also Should do-notation be avoided in Haskell?

jan.vogt
  • 1,801
  • 10
  • 27
2

The do-notation is just:

runReader r' m
    where r' = do
        x <- r "This"
        y <- r x
        z <- r y
        return z

But using (>>=) makes way more sense there.

luqui
  • 59,485
  • 12
  • 145
  • 204
Alex
  • 780
  • 4
  • 12