## An Illustrated Reader

I’m writing this down before I forget because it’s really cool. Imagine you have the following code

``````> g a b = (show a) ++ (show b)
``````
``````> h = (+5)
``````
``````> f x = g (h x) x
``````

And you run `f` through `pointfree`, because you enjoy being made to look stupid. It’ll print up

``````> f' = g =<< h
``````

You’ll stare at this going “I didn’t even say anything here was a Monad, but OK” try typing into your GHCi and… GHCi will tell you it doesn’t type check. Suitably chastened, you’ll go off to learn more Haskell elsewhere.

About a year later, you revist the problem and remember that all functions are examples of Reader monads and things start to make sense. You try

``````> import qualified Control.Monad.Reader
``````

And, hey presto, it actually works. You can even check on the command line that it works. Let’s talk about how.

# Reader, Illustrated

Start with a nice simple function `x :: initial -> intermediate`. As long as we’ve got `Control.Monad.Reader` imported, it’s automatically an `m intermediate`, where `m` means “a function taking an `input`”.

Since it’s a monadic value, we can reasonably ask what `(y =<< x)` is. Well, `y` has got to be a function that is of the form `b -> m result`. Since `m` in this case is “a function taking an `input`”, that makes `y` an `intermediate -> input -> result`. So the whole thing becomes `input -> result`.

This finally explains to me why so much of the `lens` library is written in terms of `(MonadReader s m)`: it provides an extra free level of generality as long as you recall that `(->) s` (which is a function that takes an `s`) satisfies it. i.e. you can just read it as `m b` as `s -> b`.

# Having fun

I don’t think I’ve ever published a FizzBuzz solution on the blog, so here’s one that heavily uses this reader monad trick.

``````> import Data.Maybe (Maybe(Just, Nothing), fromMaybe)
> import Data.Foldable (asum, for_)
``````
``````> import qualified GHC.Base
> -- also provides the MonadReader instance
``````
``````> toMaybe :: Bool -> a -> Maybe a
> toMaybe False _ = Nothing
> toMaybe _ value = Just value
``````
``````> fizzbuzz :: Integer -> String
> fizzbuzz = fromMaybe <\$> show <*> asum . sequence rules
>     where fb m output n = toMaybe (n `mod` m == 0) output
>           rules = [fb 15 "FizzBuzz", fb 3 "Fizz", fb 5 "Buzz"]
``````
``````> main :: IO ()
> main = for_ [1..100] \$ putStrLn . fizzbuzz
``````

Code golfers welcome.