【发布时间】:2018-06-29 05:36:41
【问题描述】:
作为编译器课程的一部分,我正在使用 haskell 构建 C# 编译器。 我正在使用状态单子,问题在于块的代码。我正在使用状态来包装声明的变量的环境。解析块时,我想扩展此状态(因为块内的声明),但之后返回原始块(因为声明不会超出块)。但是,我想先知道新更新状态的大小。所以我有下面的代码:
type EnvState = State Env (Int, Code)
type Env = M.Map String Int
fStatBlock :: [EnvState] -> EnvState
fStatBlock block = do origEnv <- get
xs <- sequence block -- prelude sequence
newEnv <- get
put origEnv
return (M.size newEnv, concatMap snd xs)
环境是 Data.Map 类型。
我的问题是 newEnv 不是序列后更新的 env,而是等于 origEnv。因此,返回的大小 100% 取决于原始 env 的大小,无论在序列中插入什么都不会改变。 (我已经测试了插入方法并且它有效)。
这是由于懒惰的评估吗?奇怪的执行顺序?或者这应该给新的,更新的环境,我在其他地方做错了吗?感谢您的帮助。
【问题讨论】:
-
能否插入
sequence函数的定义?如果这是来自base包的标准函数,那么block的类型是什么?向需要帮助的函数添加完整的类型签名总是很有用的(如果从上下文中看不清楚的话)。 -
我已经更新了代码片段,你是对的我删除了太多信息
-
也许
block实际上根本没有改变Env?尝试runState (sequence block)与一些带有block的初始地图,您希望更改内容,并确保它确实返回更改后的地图。