4

According to the introduction about ReaderT , I can only find:

ReaderT Env IO String

And it means

...is a computation which involves reading values from some environment 
of type Env (the semantics of Reader, the base monad) and performing some 
IO in order to give a value of type String.

So the order of execution will become

1. ( Already has ) some environment values          -- ReaderT Env
2. Do `IO` accroding to these pre-existing values   -- IO a
3. Use the `IO a` values to do more computations    -- IO b...z

This will requests our program has some pre-existing values as the environment, but I thought most of program need to load these environment values. Such like the database URL, debugging switcher or anything else.

Thus, we have an inverse order of execution, and which is illegal according to the Monad stack:

1. Do some `IO` to load environment settings        -- IO a first !!
2. Do more `IO` according to these settings         -- fill the env and do IO  

The monad stack will become:

IOT Env ReaderT Env

This is illegal because the IO monad can't be the base monad in monad stack. So, is there a proper way to initialize my program with external setting files ?

PS1. I noticed that the xmonad compile it's settings as a part of program. I'm still not sure whether this is the only way to "load" settings...

snowmantw
  • 1,611
  • 1
  • 13
  • 25
  • have a look at this similar question: http://stackoverflow.com/questions/11226338/missing-something-with-reader-monad-passing-the-damn-thing-around-everywhere – Rob Agar Jul 23 '12 at 08:36
  • Reading a config file is no different from 'reading' command line arguments. You don't need ReaderT, just `config <- fmap parseConfig (readFile "config")` which is no different from `number <- fmap (read.head) getArgs` as Roman is saying. – applicative Jul 23 '12 at 14:47

1 Answers1

11

First, the order of monads in the monad stack doesn't have anything to do with the order of actions that you're going to perform.

Second, you probably don't even need a stack here.

A typical program that deals with configuration is structured in the following way:

data Config = ...

readConfig :: IO Config
readConfig = do
    text <- readFile "~/.config"
    let config = ... -- do some parsing here
    return config


meat :: Reader Config Answer
meat = do
    -- invoke some operations, which get config automatically through the
    -- monad

main = do
    config <- readConfig
    let answer = runReader meat config
    print answer

You need a monad stack only if meat itself needs to perform some IO (apart from reading the config). In that case, you'd have

meat :: ReaderT Config IO Answer
meat = ...

main = do
    config <- readConfig
    answer <- runReaderT meat config
    print answer
Roman Cheplyaka
  • 37,738
  • 7
  • 72
  • 121
  • But in the 18th chapter of the book "Real World Haskell" : "We use a WriterT on top of IO because there is no IOT monad transformer. Whenever we use the IO monad with one or more monad transformers, IO will always be at the bottom of the stack" -- the order of stack still make differences ? – snowmantw Jul 23 '12 at 15:46
  • And thanks for the `main` function in your examples! I got it when I saw the function extracting values in `IO` field, and treated it as environment. – snowmantw Jul 23 '12 at 15:55
  • By the way, can I conclude that the monad transformer is not necessary, unless a computation under a monad ( Reader in the example ) will use anything in another monad ? Because your said: "You need a monad stack only if meat itself needs to perform some IO (apart from reading the config). " – snowmantw Jul 23 '12 at 16:00
  • Monad transformers are a way to combine features of multiple monads. If you need just one monad (which isn't uncommon), then you don't need transformers. Yes, the order of monad transformers in the stack matters, in general. For more info on that you can try reading my article, http://ro-che.info/articles/2012-01-02-composing-monads.html, although it does assume some familiarity with the subject. – Roman Cheplyaka Jul 23 '12 at 21:26