Skip to content

Instantly share code, notes, and snippets.

@beala
Last active August 29, 2015 14:13
Show Gist options
  • Save beala/8e518abb3ae8ab4a85df to your computer and use it in GitHub Desktop.
Save beala/8e518abb3ae8ab4a85df to your computer and use it in GitHub Desktop.
Explanation of the reader applicative/monad.
import Control.Applicative
-- Declare a struct with two readers `a` and `b`.
data Env = E {a :: Int, b :: Int}
-- Applicative (r -> _) lets us, eg, take a function that operates on Ints,
-- and instead have it operate on an Env that contains Ints. Since the new
-- function reads from the environment, we call it the Reader applicative
-- (or monad if >>= is defined).
-- Compare the "normal" add to the addInEnv below.
add :: Int -> Int -> Int
add a b = (+) a b
-- This also adds, but it gets its values from an Env. This lifts (+) into the
-- Env idiom.
addInEnv :: Env -> Int
addInEnv env = ((+) <$> a <*> b) env
-- This does the same thing as addInEnv, but does it with do notation. Technically
-- this uses >>= under the covers, but it could just as well be implemented with
-- only <*> and <$> (as shown above).
addInEnv' :: Env -> Int
addInEnv' = do
x <- a
y <- b
return (x+y)
-- Bind gives you the additional power of making readers (like a and b) depend
-- on eachother.
-- If the value returned by the reader `a` is equal to 10, actually add 1 instead
-- of `b`
addInEnv'' :: Env -> Int
addInEnv'' = do
x <- a
y <- if x == 10 then (pure 1) else b
return (x+y)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment