Я пытаюсь реализовать простой императивный язык в haskell.
Вообще говоря, моя программа представляет собой список операторов (таких как арифметическое выражение, если/тогда, блочный оператор). У моего оценщика простое состояние: стек лексических областей видимости. Лексическая область видимости — это просто сопоставление имени переменной со значением. Я нажимаю лексическую область видимости каждый раз, когда поток управления входит в функцию или блок, и всплываю, когда поток управления покидает функцию или блок.
Но я столкнулся с проблемой при попытке реализовать оценку оператора 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 находится внутри нескольких вложенных блочных операторов.
Я думаю, что могу решить эту проблему, сохраняя какое-то дополнительное состояние в моем оценщике, но такой подход выглядит не очень хорошо. Что-то мне подсказывает, что здесь мне могут помочь продолжения. Но я пока не очень хорошо понимаю продолжения.
Каков наилучший способ решить эту проблему? Мне нужна только идея, общая концепция.
Спасибо.
(>>= return)
всегда не работает. Вы должны удалить их, чтобы упростить код. И если это не неработоспособность, ваш экземплярMonad
дляEval
неисправен. - person Carl   schedule 09.05.2014