Haskell 在解释器中实现命令式返回语句

Haskell 在解释器中实现命令式返回语句,haskell,continuations,interpretation,Haskell,Continuations,Interpretation,我正在尝试用haskell实现简单的命令式语言 一般来说,我的程序是一个语句列表(如算术表达式、if/then、block语句)。我的计算器有一个简单的状态:词法作用域堆栈。词法范围只是变量名到值的映射。每当控制流进入函数或块时,我推送词法范围,当控制流离开函数或块时,我弹出词法范围 但我在尝试实现return语句的求值时遇到了一个问题。 我要做的是在主求值函数()中为return语句做一个特例: evalStatements::[Statement]->Eval可能值 --无需评估 evalS

我正在尝试用haskell实现简单的命令式语言

一般来说,我的程序是一个语句列表(如算术表达式、if/then、block语句)。我的计算器有一个简单的状态:词法作用域堆栈。词法范围只是变量名到值的映射。每当控制流进入函数或块时,我推送词法范围,当控制流离开函数或块时,我弹出词法范围

但我在尝试实现
return
语句的求值时遇到了一个问题。 我要做的是在主求值函数()中为return语句做一个特例:

evalStatements::[Statement]->Eval可能值
--无需评估
evalStatements[]=不返回任何内容
--当前语句为“return expr”,
--计算expr并跳过其余语句
评估声明(返回声明):=
levelexenv——保留当前词法范围
evalStatement ret>>=返回
--这是函数中的最后一条语句,请对其求值并保留词法范围
evalStatements[stmt]=do
res>evalStatements stmts>>=返回
evalStatement::语句->可能值
evalStatement(ExprStatemet expr)=。。。
评估声明(如果声明表达式为stmt)=。。。
但是
evalStatements
函数中的特殊情况对我来说很难看。这种方法不适用于
BlockStatement
,因为
return
语句可以在这个block语句中。 另一个问题是当return语句位于多个嵌套块语句中时,恢复词法作用域的堆栈

我想我可以通过在我的计算器中存储一些额外的状态来解决这个问题,但是这种方法看起来不是很好。有些事情告诉我,延续可以在这里帮助我。但我还不能很好地理解延续

解决这个问题的最好办法是什么?我只需要一个想法,一般概念


谢谢。

继续在这里可以工作,但他们太过分了。事实上,对于解决任何具体问题来说,延续几乎总是过火了


最简单的解决方案是将必要的逻辑放入
Eval
类型中。如果你让
Eval
包含一个“此计算以此值提前返回”的构造函数,然后让你对
(>>)
(>=)
的定义尊重这一点,一切都会自动解决。

根据单子定律,
(>=返回)
始终是禁止的。您应该删除它们以简化代码。如果它不是no op,那么
Eval
Monad
实例就被破坏了。我使用
StateT
转换器作为
Eval
类型。它看起来像
类型Eval a=StateT环境标识a
。我应该在没有monad转换器的情况下实现
Eval
monad吗?@sergeyz这其实并不简单。如何实现它有很多选择,它们都有不同的权衡。哪一个是最好的取决于很难从简短的问题描述中提取的微小细节。我的方法是备份并弄清楚
Eval
需要支持哪些操作,将它们放入带有库的DSL,然后弄清楚如何为该DSL编写解释器。感谢文章的链接,这对我非常有用。
evalStatements :: [Statement] -> Eval MaybeValue

-- nothing to evaluate
evalStatements [] = return Nothing

-- current statement is 'return expr', 
-- evaluate expr and skip the rest of statements
evalStatements (ret@(ReturnStatement _expr):_stmts) =
    leaveLexEnv -- leave current lexical scope
    evalStatement ret >>= return

-- this is last statement in function, eval it and leave lexical scope
evalStatements [stmt] = do
    res <- evalStatement stmt
    leaveLexEnv -- leave current lexical scope
    return res

evalStatements (st:stmts) =
    evalStatement st >> evalStatements stmts >>= return

evalStatement :: Statement -> MaybeValue
evalStatement (ExprStatemet expr) = ...
evalStatement (IfThenStatement expr stmt) = ...