3
data T b = E | N b (T b) (T b) 


f :: T b -> Reader Int (T Int)
f (N i l r) = ask >>= \x ->  local ((-)4) (f l) >>= \l' -> local ((-)1) (f r) >>= \r' -> return (N x l' r')
f E = return E

I have a problem with understanding how this code works. Especially, how does ask know where the environment is (in our case just Int)?

To be more precise: I am an imperative programmer and in such languages it is easy. Methods can be called on any object like: obj.f(), or we have to pass data by argument when we want function use external data.

hao
  • 10,138
  • 1
  • 35
  • 50
Gilgamesz
  • 4,727
  • 3
  • 28
  • 63
  • Possible duplicate of [Reader Monad Purpose](http://stackoverflow.com/questions/14178889/reader-monad-purpose) – MicroVirus Apr 12 '16 at 13:19
  • This is the second or third question I've seen this week about binary trees and reader monads ([eg](http://stackoverflow.com/questions/36474647/haskell-reader-monads-depth-for-each-node-in-binary-tree)). Is it from a MOOC course assignment or something? – Benjamin Hodgson Apr 12 '16 at 13:20

3 Answers3

4

That's kind of what the Reader monad does; it gives you an ask function, which "magically" pops up a value out of thin air. To actually use this, you need to call runReader, and give it the Int environment. The Reader type then automatically propagates that from the runReader call to each of the ask calls.

MathematicalOrchid
  • 61,854
  • 19
  • 123
  • 220
2

Short, hand-wavy answer. The Reader Int (T Int) value is essentially just a wrapped-up function of type Int -> (T Int). In order to run that function, we first need to extract it. We do that with runReader.

data T b = ... deriving (Show)

main = let tree = (N 10 (N 8 E E) E)
           g = f tree
           h = runReader g
       in print $ h 20

(Typically, you would simply write print $ runReader (f tree) 20; I split it up to correspond to the sketchy analogy below.)

ask (defined by the MonadReader typeclass and as implemented by the ReaderT monad transformer used to define the Reader type) essentially retrieves the value of the argument passed to h.

In some sense, the Reader Int (T Int) is an object that contains a function g that calls a function ask. runReader g creates a new function which, when called, defines a function ask that simply returns its argument, then calls g. Now when g calls ask, it gets back the argument originally passed to h.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • "The Reader Int (T Int) value is essentially just a wrapped-up function of type Int -> (T Int)" It is not obvious for me, please explain :) – Gilgamesz Apr 12 '16 at 22:32
  • I was going to attempt it, but perhaps it would be better to point you to [this explanation](http://www.mjoldfield.com/atelier/2014/08/monads-reader.html) instead. It defines a `Reader` monad directly, rather than building it up from a transformer (that implements a type class) applied to the identity monad. – chepner Apr 13 '16 at 01:06
0

I recomend reading this first. Ask is defined:

ask :: (Monad m) => ReaderT r m r
ask = ReaderT return

and reader:

newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
type Reader r = ReaderT r Identity

so

do
  r <- ask
  ...

is equivalent to

do
  r <- ReaderT return
  ...

So essentially <- just reaches into the identity monad, and grabs what ever value that will eventually be lifted by runReader R = return.

This enables global variables in haskell.

Tom Huntington
  • 2,260
  • 10
  • 20