4

根据关于的介绍ReaderT,我只能找到:

ReaderT Env IO String

这意味着

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

所以执行顺序会变成

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

这将要求我们的程序具有一些预先存在的值作为环境,但我认为大多数程序都需要加载这些环境值。例如数据库 URL、调试切换器或其他任何东西。

因此,我们有一个相反的执行顺序,根据 Monad 堆栈这是非法的:

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  

monad 堆栈将变为:

IOT Env ReaderT Env

这是非法的,因为IOmonad 不能是 monad 堆栈中的基础 monad。那么,有没有一种正确的方法来使用外部设置文件初始化我的程序?

PS1。我注意到xmonad 编译它的设置作为程序的一部分。我仍然不确定这是否是“加载”设置的唯一方法......

4

1 回答 1

11

首先,monad 堆栈中 monad 的顺序与您要执行的操作的顺序没有任何关系。

其次,您可能甚至不需要这里的堆栈。

处理配置的典型程序的结构如下:

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

只有当meat它本身需要执行一些 IO(除了读取配置)时,你才需要一个 monad 堆栈。在那种情况下,你会有

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

main = do
    config <- readConfig
    answer <- runReaderT meat config
    print answer
于 2012-07-23T08:42:59.140 回答