用continuation重写代码

ser*_*eyz 5 continuations haskell continuation-passing

我有一些代码来评估原始程序.程序是一个语句列表(表达式,块,返回语句).评估结果是最后评估的表达式.评估员也应妥善处理return陈述(即首次出现后停止评估return).

为了实现这个逻辑,我传递了特殊的回调函数(NextStep),它在当前语句之后进行下一个评估步骤.处理return语句时我不调用下一步:

data Statement = 
      Expr Int
    | Block [Statement]
    | Return Int
    deriving (Show, Eq)

data Value = 
      Undefined
    | Value Int
    deriving (Show, Eq)

type NextStep = Value -> Value

evalStmt :: Statement -> NextStep -> Value
evalStmt (Expr val) next = 
    let res = Value val
    in next res
evalStmt (Block stmts) next = evalBlock stmts next
evalStmt (Return val) next = Value val

evalBlock :: [Statement] -> NextStep -> Value
evalBlock [] next = next Undefined
evalBlock [st] next = evalStmt st next
evalBlock (st:rest) next = evalStmt st $ \ _ -> evalBlock rest next

evalProgram stmts = evalBlock stmts id

prog1 = [Expr 1, Block [Return 3, Expr 2], Expr 4] 
evalProg1 = evalProgram prog1 -- result will be Value 3
Run Code Online (Sandbox Code Playgroud)

问题是如何用continuation monad重写这段代码?我想摆脱明确传递NextStep回调evalStmtevalBlock函数.可能吗?

Dan*_*zer 7

翻译是相当机械的.

请记住,在continuation monad中,return将值提供给continuation.

evalStmt :: Statement -> Cont Value Value
evalStmt (Expr val) = 
    let res = Value val
    in return res
evalStmt (Block stmts) = evalBlock stmts
evalStmt (Return val) = cont $ \_ -> Value val

evalBlock :: [Statement] -> Cont Value Value
evalBlock [] = return Undefined
evalBlock [st] = evalStmt st
evalBlock (st:rest) = evalStmt st >> evalBlock rest

evalProgram :: [Statement] -> Value
evalProgram stmts = runCont (evalBlock stmts) id
Run Code Online (Sandbox Code Playgroud)

为了模拟早期的回报,我们只是忽略给定的延续,Return val并且只返回我们拥有的值.

  • "Cont"的monad实例被定义为以这种方式链接,因此*应该*简单地等同于`evalBlock(st:rest)= evalStmt st >> evalBlock rest` (2认同)