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.