2014/08/29

#'(function)とfuncall (Common Lisp)

 Lisp-1を使う私にとって, Common Lispの最大の謎は, funcallと#'です. Lisp-2の名前空間の仕組みさえわかってしまえば, あとはGauche(Scheme)とほとんど同じというのが, Common Lispへの私の勝手な印象です(間違っているかもしれませんが..).
 Schemeから入ると, この辺がよくわからなくなります.

 #'の正しい呼び方は, "function"です. #'は, その見た目のとおり, functionマクロのリーダマクロでした. functionは, レキシカルクロージャを生成するためのものみたいですね. (Common Lispにおけるlambdaのあれこれ(ありえるえりあ))
 しかし, 普通にlambdaと書くだけではクロージャを作らないのかというと, そういうわけでもないようです. 現代におけるCommon Lispのlambdaは, #'(lambda ...)を表すマクロなので, lambdaと書けば, #'(lambda ...)と書いたのと同じだということです. Common Lispで普段使われるlambdaは, 普通のクロージャになるのでしょうか.

 関数呼び出しの最左の式(要素?)は, ラムダ抽象か, 関数を束縛した変数である必要があります.

((lambda (x y z ...)) B C ...) ; => ○
((x y z ...) B C ...)          ; (x y z ...)がlambda式でない何か=> ×
(A B C ...)                    ; この時, Aは特殊形式 => ○
(A B C ...)                    ; 関数の名前空間にAの値(関数)が束縛されている => ○
(A B C ...)                    ; 関数の名前空間にAの値(関数)が束縛されていない => ×
 上記の○と×は, 文法的かつ変数の束縛している内容について考えた場合, 正しい記述か間違っているかという意味です. Schemeでは上から二番目の(x y z...)も問題ないのですが, Common LispではNG. Common Lispでは,  funcallは, この時(or こういった書き方をしたい時)に, 呼ばれる関数のようです. また, 最下段のケースでも, 変数の名前空間でのAに関数が束縛されている時も, funcallが使えます.

 これで, なぜfuncallをするのかという謎と, #'の使い所の謎が解けました. lambda抽象に対する#'は不要で, defunで定義した関数について, クロージャを作りたいときに, #'fなどと書けば良いことになります. funcallは, クロージャが渡された時, applyするために使うものとなります.

 funcallが必要になるのは, Lisp-2の名前空間が原因のようで, 例えば, (A B C ...)のような関数適用があった時に, 関数の名前空間におけるAが表す値(関数)と変数の名前空間におけるAが表す値(関数/クロージャを1stクラスオブジェクトとして扱えるため)を区別するためにあるようですね.

0 件のコメント :