Reputation: 1549
I am writing an interpreter for a simple language as a project at university, and there is an option to write in some debugging functionality. I thought this would be simple but after taking a break of about a week due to frustration I have come back to deal with this.
The entire haskell file is about 250 lines so I don't want to post the whole thing, but if I haven't given enough information please let me know.
I have this function
interpret_statement :: Prog -> (Var -> Val -> Vars -> o) -> Vars -> Stmt -> o
where (Var -> Val -> Vars -> o) is a debugging function - one of 2 possibilities that I choose
pure_passthrough :: Var -> Val -> Vars -> Vars -- does no IO
write_debugging_info :: Var -> Val -> Vars -> IO Vars -- does IO
I also have another function
interpret_function :: Prog -> (Var -> Val -> Vars -> o) -> Vars -> [Stmt] -> Val
which contains a line
interpret_function prog debug_function vars (x:xs) = interpret_function prog debug_function (interpret_statement prog debug_function vars x) xs
and is one of 3 lines that gives me a rigid type error saying that
Expected type: Var -> Val -> Vars -> Vars
Actual type: Var -> Val -> Vars -> o
Everything was working completely fine before trying to introduce IO. I have done it this way due to the answer of a separate question on this site that suggested I use a polymorphic function to tell the program whether to do IO or not at run-time depending on whether I receive a command line argument or not.
But now it causes problems because I have a couple of co-dependent functions that I now need to pass polymorphic variables to and from? Oh the humanity! I really think I'm getting better at Haskell guys but this one has me COMPLETELY stumped. How is the "Actualy type" Var -> Val -> Vars -> o which is polymorphic and not really specific?
Note: If I need to include more information PLEASE let me know - I have started with as little as possible so I don't overload people with unnecessary information
Upvotes: 1
Views: 152
Reputation: 4492
The call (interpret_statement prog debug_function vars x)
is in a position where it must return Vars
, it cannot return the type o
.
In interpret_function
, the return type does not depend on o
, so even if you pass in a debug function that returns an IO monad, the result of interpret_function
is not an IO monad.
My Haskell is a bit rusty, but I believe you could change interpret_function
so that its type becomes
interpret_function :: (Monad m) => Prog -> (Var -> Val -> Vars -> m Vars) -> Vars -> [Stmt] -> m Val
where m
will be either IO
or some trivial monad (perhaps this one).
Now the implementation of that particular case would go something like this:
interpret_function prog debug_function vars (x:xs) =
do vars' <- interpret_statement prog debug_function vars x
return $ interpret_function prog debug_function vars' xs
Upvotes: 4