Skip to content

Instantly share code, notes, and snippets.

@egonSchiele
Created June 10, 2013 20:51
Show Gist options
  • Star 30 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save egonSchiele/5752172 to your computer and use it in GitHub Desktop.
Save egonSchiele/5752172 to your computer and use it in GitHub Desktop.
Reader monad example
import Control.Monad.Reader
hello :: Reader String String
hello = do
name <- ask
return ("hello, " ++ name ++ "!")
bye :: Reader String String
bye = do
name <- ask
return ("bye, " ++ name ++ "!")
convo :: Reader String String
convo = do
c1 <- hello
c2 <- bye
return $ c1 ++ c2
main = print . runReader convo $ "adit"
@tabatkins
Copy link

Out of curiosity, is there any reason not to write the last line as the (imo simpler to me as a relative Haskell newb) as:

main = print $ runReader convo "adit"

?

I ask because $ is typically only used to allow the evaluation of its right hand side, when you need to call more functions to produce the argument you want to pass. Using it with a literal RHS because you needed to do some work to produce the function was confusing to me at first.

Similarly, line 17 uses $ while lines 6 and 11 use parens. That's a more typical usage of $, so I grasped it quickly enough, but the style difference for no apparent reason feels like bad form for example code. Using one or the other for all three would be nice. ^_^

@nbenns
Copy link

nbenns commented Nov 9, 2016

ok I see that shared data, but the readers are literally being unwrapped concatenated and then rewrapped... what about <$> and >>=?

@nbenns
Copy link

nbenns commented Nov 9, 2016

answered my own question:

convo = hello >>= \h -> (bye >>= \b -> return $ h ++ b)

so the reader makes sure hello bye and the returned functions are all called with the same input

alternatively with fmap (<$>):

convo = hello >>= \h -> (\b -> h ++ b) <$> bye

or with apply (<*>)

import Control.Monad.Reader

hello :: Reader String String
hello = asks $ \name -> ("hello, " ++ name ++ "!")

bye :: Reader String String
bye = asks $ \name -> ("bye, " ++ name ++ "!")

convo :: Reader String String
convo = asks (const (++)) <*> hello <*> bye

main = print . runReader convo $ "adit"

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