【问题标题】:Haskell State monad: get updated state after sequenceHaskell State monad:在序列后获取更新状态
【发布时间】: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 的初始地图,您希望更改内容,并确保它确实返回更改后的地图。

标签: haskell state monads


【解决方案1】:

正如 Justin L. 所暗示的,问题可能是 block 没有更改 Env。这是您的示例代码,未更改,添加了一些测试代码以制作完整的程序。函数setValue 产生一个EnvState,它改变了Env。在对fStatBlock 的调用中使用setValue确实会导致比基于原始env 的大小大一。

完整程序

import Control.Monad.State 
import Data.Map as M

type Code = [Int]


-- begin original code ------

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)

-- end original code -------


setValue :: String -> Int -> EnvState
setValue name value = state (\env -> ((0,[]), insert name value env))

main = do
    let env = fromList [("x", 5), ("y", 10)]
        fsb = fStatBlock [setValue "a" 15] 
    print $ fst $ fst $ runState fsb env

结果

$ ./main 
3

【讨论】:

  • 感谢您的回答!我再次查看了代码并发现了我的问题。问题是当我有嵌套块时。如果我有多个级别,无论在更深的级别发生什么,顶部的总是会返回第一个封闭块的大小。通过让 fStatBlock 的所有参数返回正确的 envSize,然后返回 return (maximum $ map fst xs, concatMap snd xs) 来解决它
猜你喜欢
  • 1970-01-01
  • 2013-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-27
  • 1970-01-01
相关资源
最近更新 更多