2016-04-20 34 views
1

我正在使用StateT-monad(與IO組合)和EitherT monad在Haskell中編寫一個小型解釋器。現在我想將整數函數應用於由interpArithmic函數解釋的值。但問題是,interparithmic本身也有EitherT InterpError (StateT Environment IO())簽名。我如何提取由interpArithmic函數解釋的值,在我的bAritHelper函數中使用它,將它們加在一起(例如)並返回那裏的新值?從Haskell的2個州獲取數據

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) 

或者是否有一些其他方式來處理錯誤並將StateT monad與IO結合使用?

PS:我想保留EitherT作爲外部monad變換器,因爲這樣我就不必在do-block中使用某種情況。

+1

你可以添加數據類型Arithmic&Value的定義嗎? InterpError和Environment也不見了,但是這並不重要,因爲你沒有在示例中使用它們 – sinelaw

回答

2

從代碼中遺漏了相當多的上下文,所以我盡我所能將它們拼湊在一起編譯。您的類型簽名也具有擴展得太遠的括號。據推測,Either也應該是EitherT

我對你想要的東西仍然有些困惑,因爲它看起來像你幾乎在那裏,但下面類似於你正在尋找什麼(這是你所期望的編譯)?也許你認爲st1 <- interpArithmic只是「解​​開一層」,因此在實際st1Value時給出了StateT ...

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) 
2

您的問題缺少一些數據類型定義,所以我從上下文中推斷出我的意思。這是我得到的:

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