Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - How to construct a program which will read some setting files?

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...

like image 201
snowmantw Avatar asked Dec 20 '22 18:12

snowmantw


1 Answers

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
like image 63
Roman Cheplyaka Avatar answered May 23 '23 00:05

Roman Cheplyaka