以下のコードが『やさしい Emacs-Lisp 講座』p.21 にある。

まず、C の場合が紹介されている。(一般的な言語の場合という意味で)

scope.c

#include <stdio.h>

static int x = 5;

void subfunc() {
    printf("x is [%d] in subfunc\n", x);
}

int main()
{
    static int x = 3;
    printf("x is [%d] in main\n", x);
    subfunc();
}

これをコンパイルして実行すると、以下のようになる。

$ gcc scope.c -o scope
$ ./scope
x is [3] in main
x is [5] in subfunc

本に書いてあるとおり、x は、それぞれの関数の中でしか参照できない。

しかし、Emacs-Lisp の場合は、以下のように書けば、ローカル変数が
他の関数の中にある変数を支配できてしまう。

(setq x 5)
(defun subfunc ()
  (insert (format "x is [%d] in subfunc\n" x)))

(defun main ()
  (let ((x 3))
    (insert (format "x is [%d] in main\n" x))
    (subfunc)))
x is [3] in main
x is [3] in subfunc

ただ、まあ、以下のようにすれば、letの束縛から離れるけれど。

(setq x 5)
(defun subfunc ()
  (insert (format "x is [%d] in subfunc\n" x)))

(defun main ()
  (let ((x 3))
    (insert (format "x is [%d] in main\n" x)))
  (subfunc))  
x is [3] in main
x is [5] in subfunc

『まったく初めての人のためのISLISP』の「スコープとクロージャ」という
項に以下に記述がある。

MonoLis Ver0.02
> (defun f(x) (g 3))
t
> (defun g(y) (+ x y))
t
> (f 2)
5

このあと、「違和感あるでしょ?」と書かれている。
そして、現在この方式を採用してるのは EmacsLisp くらいのものだ、と書かれている。

たしかに、Emacs-Lisp で、上記のコードは、そのまま動く。

(defun f(x) (g 3))
f
(defun g(y) (+ x y))
g
(f 2)
5

引数として宣言された変数の値は、その関数を飛び越えている。

それに対して、この本では、現在の scheme をはじめとする Lisp は、各関数がそれぞれスコープを持っている。そして、クロージャという仕組みも持っているとして、以下のコードが紹介されている。

(defglobal bar 1)

(defun foo (x)
  (flet ((boo (y)
              x))
     (setq bar boo)))

以下のように実行する。

> bar
1
> (foo 3)
<function>
> bar
<function>
> (funcall bar 0)
3
> (funcall bar 999)
3

(foo 3) と実行すると、boo関数が定義される。そのときに x に 3 が与えられる。
それが boo関数が実行されるときに呼び出される。
boo関数が定義されるとき、関数本体とその環境(この場合は x の値)も保持される。

これを Common Lisp で書いてみた。

(defparameter bar 1)

(defun foo (x)
  (let* ((boo (lambda (y) x)))
     (setq bar boo)))

他にいい書き方あるんだろうなあ。