私は小さなLISP /スキームインタープリターをプログラミングしていますが、次の状況に遭遇しました:
引用符で囲まれたリストにラムダが含まれている場合、それらはラムダとして解析されません。サンプルコードは次のとおりです( live on repl.it ):
(define list1 '(
(lambda (x) (+ x 1))
(lambda (y) (+ y 2))
)
)
(define add1 (car list1))
(print (add1 1))
結果は次のとおりです。
Error: ('lambda ('x) ('+ 'x 1)) is not a function [add1]
それは正常な動作ですか?ラムダは常にバインドする必要がある特別な形式だと思いました。
それが実際に期待される動作である場合:パーサーがLambdaを解析し、それをオブジェクト(たとえば、LambdaWrap型)でラップし、インタープリターがそのオブジェクトを未評価で返す場合、バインドされていないものを返すことになっているため、これは間違った動作だと思います代わりに記号。そうですか?
問題は、「ラムダとして解析される」とはどういう意味ですか?これをJavaで書いたとしましょう。
String fun = "() -> 3";
int y = fun();
文字列が解析され、ラムダ式として評価され、関数として直接使用できるとは思わないため、失敗しますか?
同じことがLISPの文字列にも当てはまり、quote
の場合も同様です。引用符で囲まれた形式は読み取られますが、評価されません。より正確には、(quote x)
の評価は、(eval x)
ではなく、x
(式自体)を返します。この式が評価時に生成する値です。
したがって、関数オブジェクトを持つ代わりに、(car list1)
を実行した後に取得するのは値のリストであり、最初の値はlambda
シンボルです。
関数のリストを作成する場合は、引数を評価する(list ...)
を使用します。
あなたは言う:
わかりましたが、なぜ内部リストが評価されるのですか?つまり、:
('lambda ('x) ('+ 'x 1))
の代わりに('lambda '( 'x ') '( '+ 'x 1') )
を取得します
リーダーは文字列を受け取り、シンボリック式である値を生成します。たとえば、car
フィールドとcdr
フィールドを持つメモリ内のオブジェクト。
あなたの質問は、これが引用された括弧などのようにトークンのリストであると想定していますが、そうではありません。この時点で、abstract構文ツリーを操作します。
この値を表示するには、システムがprint値を表示する必要があり、印刷されたフォームを読み戻すことができるようにしようとします。 repl.it
を少し遊んでみると、通常のリストがどのように印刷されるかなどがわかります。
表示される特定のメッセージは、正直なところ、フォームがREPLから見た通常の出力とは異なる、奇妙な方法で印刷されるエラーメッセージから取得されます。たぶん、他の誰かがこのエラーメッセージがそのようにフォーマットされている理由を説明できるでしょう。