Haskell State monad:在序列后获得更新状态(Haskell State monad: get updated state after sequence)

编程入门 行业动态 更新时间:2024-10-28 08:28:49
Haskell State monad:在序列后获得更新状态(Haskell State monad: get updated state after sequence)

我在haskell中构建了一个C#编译器,作为编译器课程的一部分。 我正在使用状态monad,问题在于块的代码。 我使用状态来包装已声明的变量的环境。 在解析一个块时,我想扩展这个状态(因为块内有声明),但之后返回原始块(因为这些块不会超出块的范围)。 但是,我想首先知道新更新状态的大小。 所以我有下面的代码:

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)

env是Data.Map类型的。

我的问题是,newEnv不是序列后更新后的env,而是等于origEnv。 因此,返回的大小是100%,取决于原始env的大小,并且不管序列中插入了什么内容。 (我测试了插入方法,它的工作原理)。

这是否由于懒惰的评估? 奇怪的执行顺序? 或者这应该给新的,更新的env,我是否在其他地方做错了什么? 谢谢您的帮助。

I'm building a C# compiler in haskell as part of a compilers course. I am using the state monad, and the problem lies in the code for the block. I'm using the state to wrap the env of declared vars. When parsing a block, I want to extend this state (because of declarations inside the block), but afterwards return to the original block (since declerations don't go outside the block). However, I want to know the size of the new updated state first. So I have the code below:

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)

The env is of type Data.Map.

My problem is that the newEnv isn't the updated env after sequence, but equal to the origEnv. Therefore, the size returned is 100% dependent on the size of the original env, and does not change no matter what is inserted in the sequence. (I have tested the insert method and it works).

Is this somehow due to lazy evaluation? Weird execution order? Or should this give the new, updated env and am I doing something wrong somewhere else? Thanks for the help.

最满意答案

正如贾斯汀L.所建议的那样,问题可能是该block不会改变Env 。 以下是您的示例代码(未更改),并添加了一些测试代码以制作完整的程序。 函数setValue产生一个改变Env的EnvState 。 在对fStatBlock的调用中使用setValue fStatBlock 导致比基于原始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

As Justin L. suggests, the problem probably is that block is not changing the Env. Here's your example code, unchanged, with some test code added to make a complete program. Function setValue produces an EnvState that changes the Env. Using setValue in the call to fStatBlock does result in a size that is one greater than it would be if based on the original env.

complete program

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

results

$ ./main 3

更多推荐

本文发布于:2023-08-07 03:00:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1459804.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:序列   状态   monad   Haskell   State

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!