gpt4 book ai didi

haskell - 使用 ReaderT 创建可修改的环境

转载 作者:行者123 更新时间:2023-12-02 16:07:49 24 4
gpt4 key购买 nike

我一直在关注和扩展教程 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 的想法是,我将能够通过评估器自动传递环境(维护变量绑定(bind)),并且它的使用位置将很明显,因为是对 ask 的调用。这似乎比显式地将环境作为额外参数传递更好。当我开始实现延续时,我希望使用 ContT monad 转换器执行类似的技巧,并避免为延续传递额外的参数。

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

举一个具体的例子,假设每当我计算 if 语句时,我都想将变量 it 绑定(bind)到 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 以便它修改环境。

我的第二个想法是使用本地:

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 -> Env 类型,并且由于我使用 IORef 作为环境中的值,我只能编写带有签名 Env -> IO Env 的函数。

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

最佳答案

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

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

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

如果您有这样的环境,则没有必要同时使用 IORefs,除非您正在玩具有动态范围界定的有趣游戏? IORef 的原因是什么?

关于haskell - 使用 ReaderT 创建可修改的环境,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10619678/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com