ちまちま細かい修正をしている。まず一度 Thunk を専用のオブジェクトとして作ったのを関数で表現する事にした。意味的には Thunk は引数の無い関数と同じ物ではないかと思ったから。これは後でまた戻すかも知れない。カリー化は、今の所、ユーザ定義関数(lambda)だけ出来る。プリミティブは引数の数をどうやって保存するか考え中。
式を実行するとこんなトレースが表示される。
>>> (((lambda (x y) (+ x y)) 1) 2) (((lambda (x y) (+ x y)) 1) 2) => ((lambda (x y) (+ x y)) 1) => (lambda (x y) (+ x y)) => => [ x y|((+ x y))] x := [|1] => [ y|((+ x y))] y := [|2] (+ x y) => => 3 => 3 3
関数式は評価されると [] で囲まれる。| の左が一時変数。リストとしての関数式と、環境を含んだオブジェクトとしての関数を見分けたかったので、表記を変えてみた。:= は関数適用で束縛される値。引数は Thunk 化されて関数になる。
次は無限リストの例
>>> (define ones (cons 1 ones)) (car ones) (define ones (cons 1 ones)) => => [|(cons 1 ones)] (car ones) => (cons 1 ones) => => ([|1].[|ones]) => [|1] 1
ones は (1 1 1 1...) のように無限に続くリストだけど、car に出会うまでは [|ones] のように Thunk 化されているので評価されない。
まだトレース式が醜いのでそこが課題。また、よく Haskell のデバッグしにくさは実行順序が読めないからという説があるが、遅延評価でも出鱈目の順番な訳では無くてちゃんとルール通り実行されているわけで、Lazy のデバッガを作って遅延評価を快適にデバッグする方法を研究しようと思う。もしかしたらデバッガはスクイークで作るかも知れない。大島さんがスクイークをもっと使おう!と言ってるので。