4

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

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

但是我在尝试执行return语句评估时遇到了问题。我想要做的是在主评估函数中为 return 语句做一个特殊情况(这里的来源):

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) = ...

但是函数中的特殊情况evalStatements对我来说看起来很丑。而且这种方法不适用于BlockStatement,因为return语句可以在这个块语句中。当 return 语句位于多个嵌套块语句中时,另一个问题是恢复词法范围的堆栈。

我想我可以通过在我的评估器中存储一些额外的状态来解决这个问题,但是这种方法看起来不是很好。有些东西告诉我,延续可以在这里帮助我。但我还不太了解延续。

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

谢谢。

4

1 回答 1

5

延续可以在这里工作,但它们太过分了。事实上,延续对于解决任何特定问题几乎总是矫枉过正。

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

于 2014-05-09T15:06:32.053 回答