【问题标题】:Using ReaderT to create a modifiable environment使用 ReaderT 创建可修改的环境
【发布时间】:2012-05-16 13:32:58
【问题描述】:

我一直在关注和扩展教程Write Yourself A Scheme。我有一个类型 LispVal 包裹在几层 monad 转换器中:

import qualified Data.Map as M

data LispVal   = ...
data LispError = ...

type Bindings = M.Map String (IORef LispVal)
data Env = Environment { parent :: Env, bindings :: IORef Bindings }

type IOThrowsError = ErrorT LispError IO
type EvalM = ReaderT Env IOThrowsError

使用ReaderT 的想法是,我将能够通过评估器自动传递环境(维护变量绑定),并且它的使用位置很明显,因为将调用@ 987654325@。这似乎比将环境作为额外参数显式传递更可取。当我开始实现延续时,我会想用ContT monad 转换器做一个类似的技巧,并避免为延续传递额外的参数。

但是,我还没有弄清楚如何通过这样做来修改环境。例如,定义一个新变量或设置旧变量的值。

举个具体的例子,假设每当我评估一个 if 语句时,我想将变量 it 绑定到 test 子句的结果。我的第一个想法是直接修改环境:

evalIf :: [LispVal] -> EvalM LispVal
evalIf [test, consequent, alternate] = do
  result <- eval test
  bind "it" result
  case (truthVal result) of
    True  -> eval consequent
    False -> eval alternate

这里的truthVal 是一个将Bool 分配给任何LispVal 的函数。但我不知道如何编写函数bind 以便它修改环境。

我的第二个想法是使用local

evalIf :: [LispVal] -> EvalM LispVal
evalIf [test, consequent, alternate] = do
  result <- eval test
  local (bind "it" result) $ case (truthVal result) of
    True  -> eval consequent
    False -> eval alternate

但是这里bind需要有Env -&gt; Env类型,因为我在环境中使用IORefs作为值,所以我只能写一个带有签名Env -&gt; IO Env的函数。

这是否可能,还是我需要使用StateT 而不是ReaderT

【问题讨论】:

    标签: haskell monad-transformers


    【解决方案1】:

    ReaderT 用于限定范围的只读环境。例如。在口译员中。 ReaderT 中的环境按词法嵌套,因此您可以在每次遇到绑定时扩充环境。像这样:

    eval (LetE x e1 e2) = do
        env <- ask
        v   <- eval e1
        local (M.insert x v) (eval e2)
    

    这是我的an old post 的一些示例。

    如果你有这样的环境,应该没有必要也使用IORefs,除非你在玩动态范围的有趣游戏? IORefs 的原因是什么?

    【讨论】:

    • eval for the LetE case 对于ask 而言似乎是不必要的环境。
    【解决方案2】:

    如果您想要一个可修改的上下文,您需要的是 StateT 而不是 ReaderT。读者将只允许您ask,而不是tell(如WriterT)。 State 是 Reader 和 Writer 的组合,可以随意getputmodify

    【讨论】:

    • 从技术上讲,Writertell 函数将其Monoid 参数附加到Monad 的状态,其中Stateput 函数替换了@ 987654335@的状态。
    猜你喜欢
    • 2017-02-25
    • 1970-01-01
    • 2020-09-23
    • 2015-01-29
    • 1970-01-01
    • 2014-11-14
    • 2019-04-30
    • 2016-06-25
    • 1970-01-01
    相关资源
    最近更新 更多