Skip to content

Instantly share code, notes, and snippets.

@chris-taylor
Created June 13, 2012 13:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chris-taylor/2924160 to your computer and use it in GitHub Desktop.
Save chris-taylor/2924160 to your computer and use it in GitHub Desktop.
Reader monad example
module Module1 where
import Control.Monad.Reader
data Config = Config { arg :: Int }
initialize :: IO Config
initialize = do
n <- getLine
return $ Config (read n)
function1 :: Reader Config Int
function1 = do
conf <- ask
return (arg conf + 1)
function2 :: Reader Config Int
function2 = do
conf <- ask
return (arg conf + 2)
module Module2 where
import Module1
import Control.Monad.Reader
main = do
conf <- initialize
let n1 = runReader function1 conf
let n2 = runReader function2 conf
putStrLn $ "Results: " ++ show (n1,n2)
@DavidJameson
Copy link

To me, this doesn't explain how Reader is used. In your example, you could just have easily written

n <- getLine
let n1 = function1 n
let n2 = function2 n
show (n1, n2)

The issue I have is how does one invoke a chain of functions (where each one calls the next) and have access to that global config?

@chris-taylor
Copy link
Author

You probably want to use the >>= operator to chain your functions. Let me see if I can whip up an example.

So you have some config

data Config = Config { secretNumber :: Int }

and some functions that use it

f1 :: Config -> Int -> Int
f1 (Config a) m = m + a

f2 :: Config -> Int -> Int
f2 (Config a) m = m * a

f3 :: Config -> Int -> Int
f3 (Config a) m = m - a

and you want to chain them together without having to manually pass the config to each function like this

g :: Config -> Int -> Int
g conf x = f3 conf (f2 conf (f1 conf x))

using a reader lets you define your functions as

f1 :: Int -> Reader Config Int
f1 x = do { Config a <- ask; return (a + m) }

f2 :: Int -> Reader Config Int
f2 m = do { Config a <- ask; return (a * m) }

f3 :: Int -> Reader Config Int
f3 m = do { Config a <- ask; return (a - m) }

which looks like a lot more work, but now you can chain them together like

g :: Int -> Reader Config Int
g x = f1 x >>= f2 >>= f3

and run the whole thing with

runReader (g x) (Config 42)

Is that what you're after?

@chris-taylor
Copy link
Author

NB I totally have not type checked any of the above!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment