Reputation: 688
I write simple interpreter and I would like to store variables. Up till now I have:
-- MyEnv is a map from strings into integers
type MyEnv = M.Map String Int
type TCM a = ErrorT String (StateT MyEnv IO) a
I have a definition
ms_assgn :: Assgn -> TCM()
ms_assgn (Assgn (Ident ident) exp) = do
map <- get
w1 <- ms_exp exp
put (M.insert (ident w1 map))
and I have obtained the following mistatkes:
Interpret.hs:118:5:
Couldn't match type `Envnt' with `a0 -> M.Map k0 a0 -> M.Map k0 a0'
When using functional dependencies to combine
MonadState s (StateT s m),
arising from the dependency `m -> s'
in the instance declaration in `Control.Monad.State.Class'
MonadState (a0 -> M.Map k0 a0 -> M.Map k0 a0) (StateT Envnt IO),
arising from a use of `put' at Interpret.hs:118:5-7
In a stmt of a 'do' block: put (M.insert (ident w1 map))
In the expression:
do { map <- get;
w1 <- ms_exp exp;
put (M.insert (ident w1 map)) }
Interpret.hs:118:20:
Couldn't match expected type `Integer -> Envnt -> k0'
with actual type `[Char]'
The function `ident' is applied to two arguments,
but its type `String' has none
In the first argument of `M.insert', namely `(ident w1 map)'
In the first argument of `put', namely `(M.insert (ident w1 map))'
when I commented out the last line with put and replace it with return() it makes nothing resonable, but at least it compiles. The ms_assgn function I understand this way:
What is wrong with it? Any hints?
Upvotes: 2
Views: 481
Reputation: 213758
It's just an extra set of parentheses.
M.insert (ident w1 map) -- wrong
The insert
function has type k -> a -> Map k a -> Map k a
, but those extra parentheses mean you are calling ident
as if it were a function.
M.insert ident w1 map -- correct
However, as a semantic issue, you might run into unexpected behavior if ms_exp exp
modifies the environment, because those changes would be lost. I would move that above the modification of the environment:
ms_assgn (Assgn (Ident ident) exp) = do
w1 <- ms_exp exp
map <- get
put $ M.insert ident w1 map
And a get
followed by a put
can be changed to a modify
, currying insert
. Incidentally, if you ever wondered why the Map k a
is the last argument to insert
, this is the reason.
ms_assgn (Assgn (Ident ident) exp) = do
w1 <- ms_exp exp
modify $ M.insert ident w1
And if you like, you can identify that the two do
lines are really just a single >>=
, so...
ms_assgn (Assgn (Ident ident) exp) =
ms_exp exp >>= modify . M.insert ident
You can see how, rather than using imperative do
, the data flows through the monadic bind operator >>=
into an action which modifies the environment.
Upvotes: 9