oskar132
oskar132

Reputation: 839

Reader Monad clarification

I am trying to make sense of the reader monad but can't seem to grasp what bind (>>=) does in this monad.

Here's the implementation I am analyzing:

newtype Reader e a = Reader { runReader :: (e -> a) }

instance Monad (Reader e) where 
    return a         = Reader $ \e -> a 
    (Reader r) >>= f = Reader $ \e -> runReader (f (r e)) e
  1. My first question is, why is Reader partially applied on the left hand side of bind? (Reader r) instead of (Reader r a).
  2. What goes on in this part of the definition: (f (r e)), what is it's purpose?

Thanks a lot for helping me out.

Upvotes: 2

Views: 336

Answers (3)

Alexis King
Alexis King

Reputation: 43852

My first question is, why is Reader partially applied on the left hand side of bind? (Reader r) instead of (Reader r a).

It isn’t. That use of Reader is fully saturated, as it must be. However, I can understand your confusion… remember that in Haskell, types and values are in different namespaces, and defining a datatype with data or newtype brings new names into scope in both namespaces. For example, consider the following declaration:

data Foo = Bar | Baz

This definition binds three names, Foo, Bar, and Baz. However, the part on the left-hand side of the equals sign is bound in the type namespace, since Foo is a type, and the constructors on the right hand side are bound in the value namespace, since Bar and Baz are essentially values.

All of these things have types as well, which can be helpful to visualize. Foo has a kind, which is essentially the “type of a type-level thing”, and Bar and Baz both have a type. These types can be written as follows:

Foo :: *
Bar :: Foo
Baz :: Foo

…where * is the kind of types.

Now, consider a slightly more complicated definition:

data Foo a = Bar Integer String | Baz a

Once again, this definition binds three names: Foo, Bar, and Baz. Once again, Foo is in the type namespace and Bar and Baz are in the value namespace. Their types, however, are more elaborate:

Foo :: * -> *
Bar :: Integer -> String -> Foo a
Baz :: a -> Foo a

Here, Foo is a type constructor, so it’s essentially a type-level function that accepts a type (*) as an argument. Meanwhile, Bar and Baz are value-level functions that accept various values as arguments.

Now, return to the definition of Reader. Avoiding record syntax for a moment, we can reformulate it as follows:

newtype Reader r a = Reader (r -> a)

This binds one name in the type namespace and one name in the value namespace, but the confusing part is that they’re both named Reader! This is totally allowed in Haskell, though, since the namespaces are separate. Each Reader has a kind/type in this case, too:

Reader :: * -> * -> *
Reader :: (r -> a) -> Reader r a

Note that the type-level Reader takes two arguments, but the value-level Reader only takes one. When you pattern-match against a value, you are using the value-level constructor (since you’re deconstructing a value that was built up using that same constructor), and the value only contains one value (as it must, since Reader is a newtype), so the pattern only binds a single variable.


What goes on in this part of the definition: (f (r e)), what is it's purpose?

Reader is essentially a mechanism for composing a lot of functions that all take the same argument. It’s a way to avoid having to thread a value around everywhere, since the various instances will do the plumbing automatically.

To understand the definition of >>= for Reader, let’s specialize the type of >>= to Reader:

(>>=) :: Reader r a -> (a -> Reader r b) -> Reader r b

For the purpose of clarity, we can also expand Reader r a to r -> a, just to get a better intuition for what the type actually means:

(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)

Let’s also name the arguments here for the purpose of discussion:

(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
(>>=)    f           g             =  ...

Let’s think about this for a moment. We are given two functions, f and g, and we are expected to produce a function that produces a value of type b from a value of type a. We only have one way to produce a b, and that’s by calling g. But in order to call g, we have to have an a, and we only have one way to get an a: call f! We can call f, since it only needs an r, which we already have, so we can start attaching the functions together to produce the b we need.

This is a little confusing, so it might help to see this flow of values visually:

          +------------+
          | input :: r |
          +------------+
             |       |
             v       |
+--------------+     |
| f input :: a |     |
+--------------+     |
       |             |
       v             v
  +------------------------+
  | g (f input) input :: b |
  +------------------------+

In Haskell, this looks like this:

f >>= g = \input -> g (f input) input

…or, renaming things a little to match the definition in your question:

r >>= f = \e -> f (r e) e

Now, we need to reintroduce some wrapping and unwrapping, since the real definition is on the Reader type, not (->) directly. This means we need to add some uses of the Reader wrapper and the runReader unwrapper, but otherwise the definition is the same:

Reader r >>= f = Reader (\e -> runReader (f (r e)) e)

At this point, you can check your intuition: Reader is a way to thread a value around between a lot of functions, and here we’re composing two functions, r and f. Therefore, we should need to pass the value in twice, which we do: there are two uses of e in the above definition.

Upvotes: 10

Mark Seemann
Mark Seemann

Reputation: 233150

  1. There's no partial application. Reader is a newtype definition that 'wraps' exactly one value (runReader), which is a function of the type e -> a. So, Reader r just pattern-matches the function out of the Reader wrapper. r is bound to the function of type e -> a.

  2. f is a function, as is r. r e invokes the function r with the value e, and then f is invoked with the result of that function call.

Upvotes: 1

phadej
phadej

Reputation: 12123

To answer your function, Monad is class over types of kind * -> *.

  • [Int] :: * = list of integers
  • [] :: * -> * = list
  • Reader e a :: * = reader with environment e resulting in a
  • Reader e :: * -> * = reader with environment e
  • Reader :: * -> * -> * = reader

We are lousy when we say Reader has a monad instance, when we mean Reader with any environment has a monad instance.

(Similarly, Writer w is a Monad when w is a Monoid, Writer isn't a Monad).


To answer your second question, it's easier to think in terms of the Reader e a as the same as function e -> a.

Function has the same monad definition, but without newtype wrappers and unwrappers. Think Reader = (->):

instance Monad ((->) e) where
    return x = \_ -> x -- alternatively, return = const !
    r >>= f  = \e -> f (r e) e

Yet, the join definition is probably most insightful:

join :: Reader e (Reader e a) -> Reader e a

But with bare function:

join :: (e -> e -> a) -> (e -> a)
join f e = f e e

And if we write it for Reader we have to add runReader and Reader in right places (and move variable binding to the lambda on RHS):

join f = Reader $ \e -> runReader (runReader f e) e

Upvotes: 4

Related Questions