2016-04-20 13 views
1

Ich schreibe einen kleinen Interpreter in Haskell, der die StateT-Monade (in Kombination mit IO) und die EatT Monad verwendet. Jetzt möchte ich eine ganzzahlige Funktion auf die Werte anwenden, die von der Funktion interpArithmic interpretiert werden. Aber das Problem ist, dass der interpArithmic selbst auch die EitherT InterpError (StateT Environment IO()) Signatur hat. Wie kann ich die von der interpArithmic-Funktion interpretierten Werte extrahieren, in meiner bAritHelper-Funktion verwenden, sie zusammenaddieren (zB) und dort einen neuen Wert zurückgeben?Erhalte Daten aus 2 Staaten in Haskell

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) 

Oder gibt es eine andere Möglichkeit, Fehler zu behandeln und die StateT Monade in Kombination mit IO zu verwenden?

PS: Ich möchte ETA als den äußeren Monade-Transformator behalten, weil ich auf diese Weise keine Art von Fall im Do-Block verwenden muss.

+1

Können Sie die Definitionen der Datentypen Arithmic & Value hinzufügen? Auch InterpError und Environment fehlen, aber das ist weniger wichtig, da Sie sie im Beispiel nicht verwenden – sinelaw

Antwort

2

Da ist ein bisschen Kontext in Ihrem Code fehlt, also habe ich mein Bestes getan, um es zusammenzufügen in etwas, das sich selbst kompiliert. Ihre Typ-Signaturen haben auch Klammern, die etwas zu weit hinausragen. Vermutlich sollte Either auch EitherT sein.

Ich bin immer noch leicht verwirrt von dem, was genau Sie wollen, da es scheint, als ob Sie fast da sind, aber ist das folgende ähnlich zu dem, was Sie suchen (dies kompiliert wie Sie erwarten)? Vielleicht denkst du, dass st1 <- interpArithmic nur "eine Schicht auspacken" ist und daher eine StateT ... zurückgibt, wenn tatsächlich st1 eine Value ist?

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

Ihre Frage fehlt einige Datentypen Definitionen, so habe ich aus dem Kontext abgeleitet, was ich dachte, du meintest. Hier ist, was ich habe:

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