1

I'm trying to wrap my head around the applicative instance for Reader by matching the type definition with some examples. One problem is I do not know how to use my Reader newtype.

My definition of Reader is

newtype R r a =
  R { run :: r -> a }

The type definition for (<*>) is

(<*>) :: Applicative f => f (a -> b) -> f a -> f b

Specialized for the Reader type this becomes:

(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)

So when I try:

(<*>) (+) (*2) 5 -- seems equivalent to using Reader since the types match

in the REPL I get 15. I guess this is because it computes (2*5) + 5.

How would I do the above with my Reader newtype? And is the a you see in (r -> a -> b) the same a you get from (r -> a) or am I misunderstanding something?

The Unfun Cat
  • 29,987
  • 31
  • 114
  • 156
  • 1
    you just have to pack/unpack it from `R` when defining your `Applicative` instance: `(R f) <*> (R a) = R (\r -> (f r) (a r))` – Random Dev May 31 '16 at 20:04
  • 1
    in case you already *have* the instance you have to wrap the function/values into `R` and then you can use `run`: `run (R (+) <*> R (*2)) 5` – Random Dev May 31 '16 at 20:05
  • I guess my question was not the clearest. That is what I was wondering, will upvote if you add that as an answer. Might ask you a follow up q on the applicative instance though. – The Unfun Cat May 31 '16 at 20:13
  • Possible duplicate of [How to use (->) instances of Monad and confusion about (->)](http://stackoverflow.com/questions/5310203/how-to-use-instances-of-monad-and-confusion-about) – Cactus Jun 01 '16 at 03:30

1 Answers1

4

as I said in the comments you basically have everything you need - the missing bit is just the technicality of wrapping/unwrapping the function from the R constructor.

ok here is how you make your R into a Applicative instance:

instance Applicative (R r) where
    pure a          = R (\_ -> a)
    (R f) <*> (R a) = R (\r -> (f r) (a r))

and yes this:

(<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)

then translates into:

(<*>) :: R r (a -> b) -> R r a -> R r b

once you have this the call equivalent to your example just involves wrapping/unwrapping the function from the constructor:

run (R (+) <*> R (*2)) 5

in case you get some warning about a Functor instance: you need this too:

instance Functor (R r) where
    fmap f (R a) = R (\r -> f (a r))
Random Dev
  • 51,810
  • 9
  • 92
  • 119
  • Question1) I am puzzled by why `:t (Reader (+) <*> Reader (*2))` is `Num b => Reader b b`. Can you please explain or should I ask a new q? Question2) The first argument to `(<*>)` is `r (a -> b)` - why does it then typecheck to give `(+)`, which is `(r -> a -> b)`? Thanks. – The Unfun Cat Jun 01 '16 at 18:06
  • it's because `(+)` is `Num c => c -> c -> c` - so if you look at the `r -> (a -> b)` (the essential of `R r (a -> b)`) and plug in `(+)` for it you need `r ~ c`, `a ~ c` and `b ~ c` - which yields the type (after renaming) ... btw: the first argument to `<*>` here is not `r (a -> b)` - it's `R r (a -> b)` – Random Dev Jun 01 '16 at 18:32