我试图在haskell中实现简单的命令式语言。
一般来说,我的程序是一个语句列表(如算术表达式,if / then,block语句)。我的评估者有简单的状态:词汇范围的堆栈。词法范围只是变量名称到值的映射。每当控制流进入功能或阻塞时,我推动词法范围,当控制流离开功能或阻塞时弹出。
但是我在尝试实施return
语句的评估时遇到了问题。
我想要做的是在主评估函数(sources here)中为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语句位于多个嵌套块语句内时,另一个问题是恢复词法范围的堆栈。
我认为我可以通过在评估器中存储一些额外的状态来解决这个问题,但这种方法看起来不是很好。有些东西告诉我延续可以帮助我。但我还不太了解延续情况。
解决此问题的最佳方法是什么?我只需要一个想法,一般概念。
感谢。
答案 0 :(得分:5)
延续可以在这里工作,但它们过度杀伤。事实上,对于解决任何特定问题,延续几乎总是有点过分。
最简单的解决方案是将必要的逻辑放入Eval
类型。如果你让Eval
包含&#34的构造函数;这个计算会提前返回这个值&#34;,然后让你对(>>)
和(>>=)
的定义尊重,一切都会有效自动退出。