言語ゲーム

とあるエンジニアが嘘ばかり書く日記

Twitter: @propella

俺様言語 Lazy を作る。その6。祝!遅延評価完成!

屈折四ヶ月。やりました!ようやく最初の目的だった遅延評価が完成しました!しんどいのでメモだけ。ほとんど SICP 4.1 章と同じやり方です。

  • 関数を適用する際に、引数を評価せず Thunk という物で包む。サンク = 式 + 環境
  • Thunk は force と言うメソッドで再帰的に中を force し値を取り出す。
  • 関数を適用する際に、関数自体は force する。
  • 関数を適用する際に、プリミティブなら引数も force する。

たったこれだけで遅延評価できます。Haskell の本に書いてある、パターンマッチの時だけ force するというのとはちょっと違いますが、プリミティブをパターンマッチだと思えば良いです。これだけなら簡単なのですが。。。

落とし穴はデータ構造です。Lazy はコンスセルしかデータ構造がありませんが、それでもここ数ヶ月データ構造の遅延評価をどうすれば良いのだろうと悩み続けていました。SICP 4.2.3 のように関数としてコンスセルを定義すれば簡単ですが、なんか納得行きませんでした。答えは簡単で、コンスセルの中にアクセスするには必ず car か cdr を通す事にすればよかっただけでした。一見コンスセルを force すればコンスセルの中身まで force されてしまいそうな気がするのですが、間違い。コンスセルもまた関数の一種だという事を念じながら考えると分かります。中を force するのは必ず car か cdr を通してからです。オブジェクト指向的に言うと、硬くカプセル化されているのです。結果を表示する為に、今はサボって forceAll というのでコンスセルの中まで force する関数を作ってありますが、ちゃんと文字列も Lazy の中で実装すれば要らなくなるはずです。

最近なぜか遅延評価やら Haskell やらに興味がある人が増えたらしく、焦ってしまいます。ずっとやってるのに分からないのはヤバイ!!!と思ってたので出来て良かったです。