自由変数の決定

schemeのマクロを勉強している時に、

  1 (define-syntax mcr
  2   (syntax-rules ()
  3     ((_) (print var))))
  4
  5 (define (fnc) (print var))
  6
  7 (define var 2)
  8 (mcr)
  9 (fnc)
 10 (set! var 3)
 11 (mcr)
 12 (fnc)

の実行結果が、

2
2
3
3

なのが衝撃だった。関数定義でも自由変数が使えて、その自由変数は実行時の環境で中身が決定するみたい。ちなみに、他の言語ではどうかと試してみると、Cでは、(clingを使用)

int fnc() {
    printf("%s", var);
    return 0;
}

と関数を定義しようとすると、

input_line_4:2:14: error: use of undeclared identifier 'var'
printf("%s", var);

と怒られた。しかし、pythonでは、(ipythonを使用)

def fnc():
    print(var)

var = 1

fnc()    #=> 1

となった。なんと、pythonでも同じようなことができるのだ。

まあ、関数の定義時には、自由変数が何であれ関係ないといえば、その通りなのだが、今まで出くわしたことがなかったのでちょっと驚いた。

訂正

Cでも、(clingを使用)

int var = 2;

int fnc() {
    printf("%s", var);
    return 0;
}

と関数を定義すると、エラーにならない。どうやら、関数定義時に自由変数が宣言されていなければならないようだ。