Haskell 组成延续和状态单变量转换器的正确方法

Haskell 组成延续和状态单变量转换器的正确方法,haskell,state,continuations,monad-transformers,Haskell,State,Continuations,Monad Transformers,我有一个用haskell写的原始解释器。 此解释器可以正确处理return语句() 现在我想将全局状态添加到我的解释器中。 可以从全局代码或函数的代码更改此状态 (函数的代码使用runCont运行,以提供返回逻辑) 代码如下所示: import Control.Monad.Cont import Control.Monad.State type MyState = String data Statement = Return Int | GetState | SetState MyState

我有一个用haskell写的原始解释器。 此解释器可以正确处理
return
语句()

现在我想将全局状态添加到我的解释器中。 可以从全局代码或函数的代码更改此状态 (函数的代码使用
runCont
运行,以提供
返回逻辑)

代码如下所示:

import Control.Monad.Cont
import Control.Monad.State

type MyState = String
data Statement = Return Int | GetState | SetState MyState | FuncCall [Statement] deriving (Show)
data Value = Undefined | Value Int | StateValue MyState deriving (Show)

type Eval a = StateT MyState (Cont (Value, MyState)) a

runEval ::(Eval Value) -> MyState -> (Value, MyState)
runEval eval state = runCont (runStateT eval state) id

evalProg :: [Statement] -> Value
evalProg stmts = fst $ runEval (evalBlock stmts) $ ""

evalBlock :: [Statement] -> Eval Value
evalBlock [] = return Undefined
evalBlock [stmt] = evalStatment stmt
evalBlock (st:stmts) = evalStatment st >> evalBlock stmts

evalStatment :: Statement -> Eval Value
evalStatment (Return val) = do
    state <- get
    lift $ cont $ \_ -> (Value val, state)
evalStatment (SetState state) = put state >> return Undefined
evalStatment (FuncCall stmts) = do
    -- I don't like this peace of code
    state <- get
    (value, newState) <- return $ runEval (evalBlock stmts) $ state
    put newState
    return value
evalStatment GetState = get >>= return . StateValue

test2 = evalProg [SetState "Hello", FuncCall [SetState "Galaxy", Return 3], GetState] -- result is StateValue "Galaxy"
import Control.Monad.Cont
进口控制单体状态
类型MyState=String
数据语句=返回Int | GetState | SetState MyState | FuncCall[Statement]派生(显示)
数据值=未定义|值Int |状态值MyState派生(显示)
类型Eval a=StateT MyState(Cont(Value,MyState))a
runEval::(Eval值)->MyState->(值,MyState)
runEval eval state=runCont(runStateT eval state)id
evalProg::[语句]->值
evalProg stmts=fst$runEval(evalBlock stmts)$“”
evalBlock::[Statement]->Eval值
evalBlock[]=返回未定义
evalBlock[stmt]=evalStatment stmt
evalBlock(st:stmts)=evalStatment st>>evalBlock stmts
evalStatment::语句->评估值
evalStatment(返回值)=do
状态(值val,状态)
evalStatment(设置状态)=放置状态>>返回未定义
evalStatment(functcall stmts)=do
--我不喜欢这种代码的和平
状态=返回。状态值
test2=evalProg[SetState“Hello”,FuncCall[SetState“Galaxy”,Return 3],GetState]--结果是StateValue“Galaxy”
这段代码工作正常,但我不喜欢这段代码的
evalStatment(funccallstmts)
部分。 我将解释器的当前状态传递给
runEval
函数, 然后返回修改后的状态并将其设置为新解释器的状态

是否有可能改进此代码?我是否可以以某种方式生成函数的代码(
FuncCall
) 隐式操作解释器的状态(不获取当前状态并运行函数的
明确地编码和设置解释器的新状态)?

我建议您将基本Monad更改为

type Eval a = ContT Value (State MyState) a
这样,
State MyState
部分位于“monad transformer stack”的底部,您将能够更轻松地只提取上面的延续部分而不影响状态。然后,
FuncCall
案例可以简单地

evalStatment (FuncCall stmts) = lift $ runContT (evalBlock stmts) return
当然,这也需要重写一些其他部分。但不多,而且大部分都变得更简单了!以下是我需要更改的所有部分:

type Eval a = ContT Value (State MyState) a

runEval eval state = runState (runContT eval return) state 

evalStatment (Return val) = ContT $ \_ -> return (Value val)

evalStatment (FuncCall stmts) = lift $ runContT (evalBlock stmts) return

您是否只需要
sequence::Monad m=>[ma]->m[a]
?可能后跟
liftM last::Monad m=>m[a]->ma