用延续重写代码 [英] Rewriting code with continuations

查看:111
本文介绍了用延续重写代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些评估原始程序的代码。程序是一个语句列表(表达式,块,返回语句)。评估结果是上次评估的表达式。另外,评估人员应该正确处理 return 语句(即在第一次出现 return 时停止评估)。

I have some code that evaluates primitive programs. Program is a list of statements (expression, block, return statement). Result of evaluation is last evaluated expression. Also evaluator should properly treat return statement (i.e. stop evaluation after first occurrence of return).

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

To implement this logic I pass special callback function (NextStep) which make next evaluating step after current statement. I don't call next step when handling return statement:

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

问题是如何用连续monad重写这段代码?我想摆脱在 evalStmt evalBlock NextStep 回调$ c>函数。是否有可能?

The question is how can I rewrite this code with continuation monad? I want to get rid of explicitly passed NextStep callback in evalStmt and evalBlock functions. Is it possible?

推荐答案

翻译是相当机械的。

请记住,在继续monad中, return 会将值提供给继续。

Keep in mind that in the continuation monad, return feeds the value into the 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

为了模拟早期收益,我们只是忽略给予返回val 的延续,然后返回我们的值。

And to simulate early returns, we just ignore the continuation given to Return val and just return the value we have.

这篇关于用延续重写代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆