Reputation:
I'm writing a small interpreter in Haskell that uses the StateT-monad (in combination with IO) and the EitherT monad. Now I want to apply an integer function to the values interpreted by the interpArithmic function. But the problem is that the interpArithmic itself also has the EitherT InterpError (StateT Environment IO ())
signature. How can I extract the values interpreted by the interpArithmic function, use it in my bAritHelper function, add them together (for example) and return there new value?
bArithHelper :: Arithmic -> Arithmic -> (Integer -> Integer -> Integer) -> EitherT InterpError (StateT Environment IO Value)
bArithHelper a b func =
-- Body of this function is completely broken, don't know how to fix this.
do
st1 <- interpArithmic a
st2 <- interpArithmic b
return $ do
env1 <- get st1
env2 <- get st2
return Num
liftM $
-- This function interpretes an arithmic expression and returns it's result.
-- An error message (int the form of Error) is returned in case something goes wrong.
interpArithmic :: Arithmic -> Either InterpError (StateT Environment IO Value)
interpArithmic (ConstInteger a) = return (Num a)
interpArithmic (BinaryArithmicExpression Add a b) = bArithHelper a b (\x -> \y -> x + y)
Or is there some other way to handle errors and use the StateT monad in combination with IO?
PS: I would like to retain EitherT as the outer monad transformer, because that way I don't have to use some sort of case in do-block.
Upvotes: 1
Views: 115
Reputation: 16563
Your question is missing some data type definitions, so I inferred from the context what I thought you meant. Here's what I got:
module Main where
import Control.Monad.Trans.Either
import Control.Monad.Trans.State
data InterpError = InterpError () deriving (Show)
data Environment = Environment () deriving (Show)
data Op = Add deriving (Show)
data Value = Num Integer deriving (Show)
data Arithmic = ConstInteger Integer
| BinaryArithmicExpression Op Arithmic Arithmic
deriving (Show)
bArithHelper :: Arithmic -> Arithmic -> (Integer -> Integer -> Integer) -> EitherT InterpError (StateT Environment IO) Value
bArithHelper a b func = do
Num st1 <- interpArithmic a
Num st2 <- interpArithmic b
return $ Num $ func st1 st2
-- This function interpretes an arithmic expression and returns it's result.
-- An error message (int the form of Error) is returned in case something goes wrong.
interpArithmic :: Arithmic -> EitherT InterpError (StateT Environment IO) Value
interpArithmic (ConstInteger a) = return (Num a)
interpArithmic (BinaryArithmicExpression Add a b) = bArithHelper a b (\x -> \y -> x + y)
main :: IO ()
main = do
res <- runStateT (runEitherT $ interpArithmic (BinaryArithmicExpression Add (ConstInteger 2) (ConstInteger 3))) $ Environment ()
print res
Upvotes: 1
Reputation: 3739
There's quite a bit of context missing from your code so I've done my best to piece it together into something that compiles by itself. Your type signatures also have parentheses that extend a bit too far out. Presumably Either
was meant to be EitherT
as well.
I'm still slightly confused by what exactly you want since it seems like you're almost there, but is the following akin to what you're looking for (this compiles as you would expect)? Perhaps you think that st1 <- interpArithmic
is only "unwrapping one layer" and therefore gives back a StateT ...
when in fact st1
is a Value
?
import Control.Monad.Trans.Except
import Control.Monad.Trans.State
type EitherT = ExceptT
data Arithmic = ConstInteger Integer | BinaryArithmicExpression Exp Arithmic Arithmic
data Value = Num Integer
data Exp = Add
type InterpError = String
type Environment = String
getVal :: Value -> Integer
getVal (Num x) = x
bArithHelper :: Arithmic -> Arithmic -> (Integer -> Integer -> Integer) -> EitherT InterpError (StateT Environment IO) Value
bArithHelper a b func =
do
st1 <- interpArithmic a
st2 <- interpArithmic b
return $ Num (func (getVal st1) (getVal st2))
interpArithmic :: Arithmic -> EitherT InterpError (StateT Environment IO) Value
interpArithmic (ConstInteger a) = return (Num a)
interpArithmic (BinaryArithmicExpression Add a b) = bArithHelper a b (\x -> \y -> x + y)
Upvotes: 1