Reputation: 188
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.
Upvotes: 2
Views: 871
Reputation: 1423
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
Upvotes: 2