Haskell状态monad:在序列之后获取更新的状态
作为编译器课程的一部分,我正在haskell中构建一个C#编译器。 我使用的是state monad,问题在于块的代码。我正在使用state包装声明变量的env。在分析一个块时,我想扩展这个状态(因为块内有声明),但之后返回到原始块(因为删除不会超出块)。但是,我想先知道新更新状态的大小。所以我有下面的代码:Haskell状态monad:在序列之后获取更新的状态,haskell,state,monads,Haskell,State,Monads,作为编译器课程的一部分,我正在haskell中构建一个C#编译器。 我使用的是state monad,问题在于块的代码。我正在使用state包装声明变量的env。在分析一个块时,我想扩展这个状态(因为块内有声明),但之后返回到原始块(因为删除不会超出块)。但是,我想先知道新更新状态的大小。所以我有下面的代码: type EnvState = State Env (Int, Code) type Env = M.Map String Int fStatBlock :: [EnvState] -&
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)
type EnvState=状态Env(Int,code)
类型Env=M。映射字符串Int
fStatBlock::[EnvState]->EnvState
fStatBlock block=do origEnv正如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
请插入序列
函数的定义好吗?如果这是base
包中的标准函数,那么块的类型是什么?在需要帮助的函数中添加完整的类型签名总是很有用的(如果上下文中不清楚的话)。我已经更新了代码片段,你是对的,我删除了太多的信息可能block
根本没有改变Env
?尝试runState(sequence block)
,使用带有块的一些初始映射,您希望更改内容,并确保它确实返回更改的映射。感谢您在回答中付出的努力!我再次查看了代码,发现了我的问题。问题是当我有嵌套块时。如果我有多个级别,那么最上面的一个总是返回第一个封闭块的大小,不管在更深的级别发生什么。通过让fStatBlock的所有参数返回正确的envSize,然后返回return(最大$map fst xs,concatMap snd xs)
$ ./main
3