Lisp In Small Piecesの1.6のまとめ。スコープの所が良くわかっていない。
(自作処理系の)関数の実装には、(Schemeの)関数を使うのがよい。最も簡単な実装。
(define (invoke fn args) (if (procedure? fn) (fn args) (wrong "Not a funstion" fn)))
練習問題1.7、1.8でさらに詳しくやるっぽい。
関数適用におけるエラーについて
- 関数の場所(listのcar部分)にある項を評価する
- その値が関数適応できない値の時、エラーを発生させる
- 引数を左から右へ評価する
- 引数の数と、関数のarity(オペランドの個数)の数を比較し、同じなら関数適用を行い、数が違う場合はエラーを発生させる。
最初に引数の数をチェックしてもよい。
1.6.1 Dynamic and Lexical Binding
全ての評価は、特定の環境下で行われる。3章ではもっと込み入った構造(unwind-protectなど)を取り扱う。
もう一つの大事な点は、はダイナミックバインディングとレキシカルバインディング。レキシカルLispでは、関数は、その変数によって拡張された、定義時の環境で評価される。ダイナミックLispでは、関数は現在(実行時)の環境を拡張する、つまりアプリケーションの環境で評価される。
最近の流行はレキシカルLispである。pure schemeでは、たった一つのbinidng フォームlambdaを持つ。
(define (foo x) (list x y)) (define (bar y) (foo 1991))
lexical Lispの時、fooの中のyはグローバル変数のyを示す。
(define y 0) (define (bar 100) (foo 3)) ;; => ((1991 0) (3 0)) in lexical Lisp (define (bar 100) (foo 3)) ;; => ((1991 100) (3 0)) in dynamic Lisp
新しいスペシャルフォーム function を導入する。Lambda formを引数に取りclosureを作る。これにより、関数と定義時の環境が関係づけられる。このクロージャが適用されたとき、現在の環境を拡張するのではなく、定義時の環境を拡張する
Common Lispでは、(declare (special x))でダイナミックスコープになる。
1.6.2 Deep or Shallow Implemantation
環境をalistで表現した場合、検索(lookuo)のコストはリストの長さに比例する。これをdeep bindingと言う。もう一つ、shallow bindingという実装方法がある。
http://www.geocities.co.jp/SiliconValley-Bay/9285/ELISP-JA/elisp_147.html
良くわからないけど、速度に関する実装の話なので、とりあえず置いておく。