从 Haskell 中的 2 个州获取数据

Get data from 2 states in Haskell

我正在 Haskell 中编写一个小型解释器,它使用 StateT-monad(结合 IO)和 EitherT monad。现在我想将一个整数函数应用于由 interpArithmic 函数解释的值。但问题是 interpArithmic 本身也有 EitherT InterpError (StateT Environment IO ()) 签名。我如何提取由 interpArithmic 函数解释的值,在我的 bAritHelper 函数中使用它,将它们加在一起(例如)并 return 有新值?

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 中使用某种大小写。

您的代码中缺少相当多的上下文,因此我已尽力将其拼凑成可以自行编译的代码。您的类型签名也有延伸有点过远的括号。大概 Either 也意味着 EitherT

我仍然对您到底想要什么感到有点困惑,因为您似乎快到了,但是以下内容是否与您正在寻找的内容类似(这会按您的预期进行编译)?也许您认为 st1 <- interpArithmic 只是 "unwrapping one layer",因此返回 StateT ... 而实际上 st1Value

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)

你的问题缺少一些数据类型定义,所以我从上下文中推断出我认为你的意思。这是我得到的:

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