関数型言語の勉強にSICPを読もう - (59) 4章 - 超言語的抽象(220ページ) C++でSchemeインタプリタを作ろう8
実装というか設計に迷いが。
(begin (define func (lambda (a) "test")) (func 3) )
まず前提として、上の式を評価すると、"test" が返ることが期待されます。(Gaucheで試しました)
SICPによれば(func 3)は以下の順に評価されます。
1. (予約語でない語句 数値)という形なので関数適用と判断される
2. なのでまず func が evalされます。
3. 次に 3が evalされます。数値は self-evaluatingなので評価されても3のままです。
4. 2, 3の evalの結果をapplyで実行します。
具体的なコードは
(apply 2の結果 3の結果)
で、今戸惑っているのは 2の部分。
SICPのコード例によれば func は予約語でないため変数扱いであるから、funcをevalすると(lambda (a) "test")をあらわすオブジェクトが返ります。
Frameのリストから一致する変数の値がlook-up-variableで返されるというわけです。
で、このまま3, 4のステップに突入すると
(apply (lambda (a) "test") 3)
という形になります。
applyでは (lambda (a) "test")をあらわすオブジェクトは、evalSequenceに渡されて eval されます。
lambdaをあらわすオブジェクトは eval されると procedure をあらわすオブジェクトになるのですが、ここで eval がひとつ足りないことに気づきます。
applyに渡る時点で procedure になっていないといけないのに lambda のオブジェクトとなっています。つまり eval が1段階で抜けています。
ちょっと説明が分かりづらいと思うのですが、今のロジックは以下のコードでは適切に動きますが、funcという変数を介していると eval が足りなくなってしまうという話です。
(begin ((lambda (a) "test" 3) )
今思いつく解決策は apply の直前にオペレータを複数回 eval して、 procedureオブジェクトになったら apply を callするという方法なのですが
などがとても気になります。