レキシカルとダイナミック:2種類の入れ子

変数のように、あるLisp Objectを名前で参照するときに、2つの入れ子構造を使い分けます。これらをレキシカル・スコープとダイナミック・スコープと呼びます。

スコープとは、ある名前(シンボル)とLisp Objectの結びつき(バインディング、binding)が見える(有効である)ソースコードの範囲です。

入れ子の内側にいて、ある名前の値を参照しようとすると、その名前の一番内側のバインディングが見えるようになっています。同じ名前の外側のバインディングは一時的に見えなく(shadowed)なります。

レキシカル・スコープ
レキシカルな、つまり、プログラムのソース・コードの字面上でのオペレータの入れ子構造によって範囲(スコープ)が表されます。

KISS>(defun f (a)                              ;; ----------+
       ;; a is an argument given when called   ;;           |
       (let ((result (list a)))                ;;           |
         (let ((a 0))                          ;;           |
           ;; a is 0                           ;; -------+  |
           (setq result (cons a result))       ;;        |  |
           (let ((a 10))                       ;;        |  |
             ;; a is 10                        ;; ----+  |  |
             (setq result (cons a result))     ;;     |  |  |
             (let ((a 100))                    ;;     |  |  |
               ;; a is 100                     ;; --+ |  |  |
               (setq result (cons a result)))  ;; --+ |  |  |
             ;; a is back to 10                ;;     |  |  |
             (setq result (cons a result)))    ;; ----+  |  |
           ;; a is back to 0                   ;;        |  |
           (setq result (cons a result)))      ;; -------+  |
         ;; a is back to the original argument ;;           |
         (setq result (cons a result))         ;;           |
         result))                              ;; ----------+
f

KISS>(f -1)
(-1 0 10 100 10 0 -1)

KISS>
ダイナミック・スコープ
ダイナミックな、つまり、実行時のオペレータ(関数やスペシャル・オペレータ)の動的な呼び出し関係の入れ子構造によってバインディングが見える範囲(スコープ)が決定します。

KISS>(defun foo (x)
       (dynamic-let ((y x))
         (bar 1)))
foo ;; 関数foo定義完了
                
KISS>(defun bar (x)
       (+ x (dynamic y)))
bar ;; 関数bar定義完了

                
KISS>(foo 2)
;;(foo 2)により関数fooが呼び出される
;;  (foo 2)
;;    |  関数fooの引数であるレキシカル変数xは2
;;    |  関数foo内の(dynamic-let ((y x))で、xはいま2なので、
;;    |  ダイナミック変数yの値は2に設定される
;;    |  (dynamic-let ((y 2))
;;    |
;;    |    関数foo内の (bar 1) により関数barが呼び出される
;;    |    (bar 1)
;;  |      |関数barの引数であるレキシカル変数xは1
;;    |      |
;;    |      |関数bar内の (dynamic y) は
;;    |      |実行中の関数foo内の(dynamic-let ((y 2))による
;;    |      |ダイナミック変数yを参照
;;    |      |つまり(dynamic y)は2となる
;;    |      |
;;    |    (+ x (dynamic y)) は、(+ 1 2)になる
;;    |    3を返す
;;    |
;;    3を返す

3

KISS>




コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です