第六回
「大域脱出(exit)の追加」
今までは、CPS の話はいったん置いてインタプリタに機能を追加していたわけですが、今回からはいよいよ CPS の話がインタプリタの作成と絡んできます。
今回の目標は exit 文を導入することです。
まずは、入力の構文を次のように拡張します。
type expr_t = ...
| Exit of expr_t
引数の expr_t は exit 文で返す値です。
例えば 1 + exit (2 + 3) なら 1 + の実行は捨て、
2 + 3 の結果である 5 が返って来ます。
また、1 + exit (2 + exit (4)) のようなものの場合は、
4 が返って来ます。
さて、exit 文を実装するには大きく分けて次の3つの方法があります。
(1) OCaml の exception を使う方法
ずるのようなものですが、今までのインタプリタをほとんど書き換えずに
実装できるので、やってみるといいかもしれません。
(2) 正常終了と exit の場合をいちいち区別して扱う方法
実行結果である value_t 型を、正常終了した場合と exit の場合の2通りに分ける方法です。
「値が返って来たときに、それが exit だったら何もせずにその値をそのまま返す」というのを
値を受け取る箇所そこらじゅうに挿入します。
この方法は、インタプリタの大きな構造を変える必要はありませんが、
value_t の値が exit の場合かどうかでいちいち場合分けが必要になり、
書き換える量はそれなりになります。
とはいえ、けっこう単純な作業なので、
四則演算だけのインタプリタあたりで一度実装してみると
理解が深まっていいかもしれません。
(3) 全体を CPS に書き換える方法
今回はこれでいきます。
インタプリタ全体を CPS に書き換えてしまいます。
今まで eval expr env となっていたのを
eval expr env cont にするわけです。(当然、引数名は人によって違うと思いますが)
ここで、cont が継続です。
CPS になれば、継続を捨てさえすればいつでも実行を中断できます。
この方法は全体を書き換えなくてはいけないので大変ですが、
exit 以外にもいろいろな大域的ジャンプを実装できるようになります。
(実際、次回はもっと激しいジャンプをする命令を追加します!)
=============================================================
問題(質問、相談可)
これまでのインタプリタを CPS に書き換えた上で exit 文を追加せよ。
=============================================================
closure のところで悩むかもしれません。
その場合は、四則演算のみのインタプリタ(か、それに環境を加えたもの)で
やってみるといいかもしれません。
ヒント:CPS変換は第二回でやりました。
おおまかに言ってしまうと、
1.それまで値を受け取ってから何かしていた部分では、値を貰った後にすることを継続として書く。
2.それまで値を返していたところでは、継続に値を渡すようにする。
だけです。
とりあえずやってみましょう!