CPS を使用して、Python インタープリターでの制御フローの実装を簡素化しようとしています。具体的には、return
/ break
/continue
を実装するときは、状態を保存して手動で巻き戻す必要があり、面倒です。この方法で例外処理を実装するのは非常に難しいと読んだことがあります。私が望むのは、各eval
関数が制御フローを次の命令または別の命令に完全に向けることができるようにすることです。
私よりも経験豊富な何人かは、これを適切に処理する方法として CPS を調べることを提案しました。インタープリターでの制御フローを単純化する方法は本当に気に入っていますが、これを達成するために実際にどれだけの作業を行う必要があるかはわかりません。
AST で CPS 変換を実行する必要がありますか? この AST をより小さな下位レベルの IR に下げてから、それを変換する必要がありますか?
どこでも成功の継続を受け入れるようにエバリュエーターを更新する必要がありますか? (私はそう仮定しています)。
私は、CPS 変換を一般的に理解していると思います。目標は、すべての式を含む AST 全体を通して継続をスレッド化することです。
Cont
また、ホスト言語が Haskell であるため、モナドがどこに収まるかについても少し混乱しています。
編集: 問題の AST の要約版を次に示します。これは、Python ステートメント、式、および組み込み値の 1 対 1 のマッピングです。
data Statement
= Assignment Expression Expression
| Expression Expression
| Break
| While Expression [Statement]
data Expression
| Attribute Expression String
| Constant Value
data Value
= String String
| Int Integer
| None
ステートメントを評価するには、次を使用しますeval
。
eval (Assignment (Variable var) expr) = do
value <- evalExpr expr
updateSymbol var value
eval (Expression e) = do
_ <- evalExpr e
return ()
式を評価するには、次を使用しますevalExpr
。
evalExpr (Attribute target name) = do
receiver <- evalExpr target
attribute <- getAttr name receiver
case attribute of
Just v -> return v
Nothing -> fail $ "No attribute " ++ name
evalExpr (Constant c) = return c
全体の動機となったのは、休憩を実装するために必要な悪ふざけでした。break の定義は合理的ですが、while の定義に対して行うことは少し多すぎます。
eval (Break) = do
env <- get
when (loopLevel env <= 0) (fail "Can only break in a loop!")
put env { flow = Breaking }
eval (While condition block) = do
setup
loop
cleanup
where
setup = do
env <- get
let level = loopLevel env
put env { loopLevel = level + 1 }
loop = do
env <- get
result <- evalExpr condition
when (isTruthy result && flow env == Next) $ do
evalBlock block
-- Pretty ugly! Eat continue.
updatedEnv <- get
when (flow updatedEnv == Continuing) $ put updatedEnv { flow = Next }
loop
cleanup = do
env <- get
let level = loopLevel env
put env { loopLevel = level - 1 }
case flow env of
Breaking -> put env { flow = Next }
Continuing -> put env { flow = Next }
_ -> return ()
ここで実行できる単純化は他にもあると確信していますが、核となる問題は、状態をどこかに詰め込み、手動で巻き戻すことです。CPS によって簿記 (ループ出口ポイントなど) を状態に詰め込み、必要なときにそれらを使用できるようになることを願っています。
私はステートメントと式が分かれているのが嫌いで、CPS 変換の作業が増えるのではないかと心配しています。