2016-07-26 14 views
1

が、私は次の2つのコードスニペットを理解しようとしている字句-てみましょう:のelispのラムダ、引用、および

(defun make-adder1 (n) `(lambda (x) (+ ,n x))) 

(defun make-adder2 (n) (lexical-let ((n n)) (lambda (x) (+ n x)))) 

これらの両方は、呼び出し可能オブジェクトを生成するように見える:

(funcall (make-adder1 3) 5) ;; returns 8 
(funcall (make-adder2 3) 5) ;; returns 8 

これらの両方の仕事を。私は2つの主な質問があります:

1)私は2つのアプローチの間の "引用レベル"の相違を理解していません。最初のケースでは、ラムダ式が引用されています。つまり、値の代わりに "シンボル自体"が返されます。 2番目のケースでは、ラムダのステートメントが評価されるように見えるので、ラムダの値が返されます。しかし、これらはどちらもfuncallで動作します。 funcallをed関数で使用する場合は、引用符で囲む必要があります。レキシカルでは何らかの引用が自動的に行われますか?これは驚くべきことではありませんか?

2)このトピックに関する他の記事を読むと、最初のアプローチは特定の状況下では破壊され、他の言語ではラムダと高次関数を使用することで期待されるものから逸脱することを理解しています。デフォルトでは動的スコープがあります。誰かがこの違いを明白にして説明するコードの具体的な例を挙げることはできますか?

+1

はこれが重複しなければなりませんが、私はそれを探すために時間を持っていません... – Drew

答えて

2

最初の例では、結果の関数に変数nはありません。これはちょうど(lambda (x) (+ 3 x))です。ラムダに自由変数がない、すなわちクロージャのバインディングに保持する必要のある変数がないため、字句的結合は必要ありません。変数nを使用する必要がない場合は、関数の使用時にという変数としてを使用する必要がない場合、つまり関数定義時の値(= 3)が必要な場合は、最初の例だけが必要です。

(fset 'ad1 (make-adder1 3)) 

(symbol-function 'ad1) 

戻り値:

(lambda (x) (+ 3 x)) 

第二の例は、実際には、作成して複雑なクロージャを適用する機能が何であるかを生成します。

(fset 'ad2 (make-adder2 3)) 

(symbol-function 'ad2) 

戻り

(lambda (&rest --cl-rest--) 
    (apply (quote (closure ((--cl-n-- . --n--) (n . 3) t) 
         (G69710 x) 
         (+ (symbol-value G69710) x))) 
     (quote --n--) 
     --cl-rest--)) 

第三の選択肢はlexical-bindingファイルローカル変数を使用して、最も簡単な定義を使用することです。これにより、単純なクロージャが作成されます。

;;; foo.el --- toto -*- lexical-binding: t -*- 
(defun make-adder3 (n) (lambda (x) (+ n x))) 

(fset 'ad3 (make-adder3 3)) 

(symbol-function 'ad3) 

戻り値:

(closure ((n . 3) t) (x) (+ n x)) 

(symbol-function 'make-adder1) 

戻り値:

(lambda (n) 
    (list (quote lambda) 
    (quote (x)) 
    (cons (quote +) (cons n (quote (x)))))) 


(symbol-function 'make-adder2) 

戻り値:

(closure (t) 
    (n) 
    (let ((--cl-n-- (make-symbol "--n--"))) 
     (let* ((v --cl-n--)) (set v n)) 
     (list (quote lambda) 
     (quote (&rest --cl-rest--)) 
     (list (quote apply) 
      (list (quote quote) 
      (function 
       (lambda (G69709 x) 
       (+ (symbol-value G69709) x)))) 
      (list (quote quote) --cl-n--) 
      (quote --cl-rest--))))) 


(symbol-function 'make-adder3) 

戻り

(closure (t) (n) (function (lambda (x) (+ n x))))