2008年1月4日金曜日

Chapter 6 Variables

前説

CLには、lexical な variables と dynamic な variables がある。

Variable Basics


  • 型は、valuesが運ぶ。型チェックはランタイムに実施。(dynamicaly typed)
  • 全ての型エラーは検知される。(strongly typed)
  • 少なくとも概念的には、全てのvaluesは、objectsへの参照である。なので、別の a value を a variable に設定するということは、もとのa value(であるところのa object)に影響を与えない。
  • mutable な objects については、それ自体を変更する方法もある。
  • 新しいvariablesを導入するには、DEFUNが使える。DEFUNはそれへの呼び出し毎に引数とvaluesのbindingsを生成する。
  • arguments = function parameters。
  • function parametersは他のvariablesと同じようにobject referencesを保持している。なので、functionのbodyにてfunction parametersに新しいvaluesを割り当てても、他のbindingsには影響はない。
  • しかし、functionに渡されたobjectsがmutableであるならば、bodyの中でそのobjectsを変更した場合、その変更はthe callerからは見える。the callerとthe calleeは同じojbectを参照しているから。
  • LETもbindingsを作る。
  • DEFUNやLETを the binding form と呼ぶ。(それ自身の構造の中でのみ有効なvariablesを導入可能なものは、すべてbinding formと呼ばれる)
  • binding forms をネストした場合、同じ名前の variablesについては、外側のbindingsは内側のbindingsによってshadowされる。
  • このようにbinding formsのネストの構造が、scopesの区切りになることは、lexical variablesについてもdynamic variablesについても同様である。



Lexical Variables and Closures

lexically scoped variables は、それを導入した binding form の中でしか参照できない。これが基本ルール。しかし、その binding formの評価結果がa function であって、それが、先のlexical scoped variablesを参照していたらどうなるだろう。これもアリである。そのbindingは、評価結果である function object が存在する限りそれにくっついている。これをクロージャという。クロージャが保持しているのはvalues自体ではなくbindingsである。よって、新しいvaluesをクロージャ内で割り当てれば、グローバル変数のように、valuesが変化していきそれを保持できる。
そうか、Schemeを環境モデルで理解するとき 関数定義+環境をクロージャと考えるが、CLではlexically scoped variablesのbindingsを包み込んでいるlambdaのことをクロージャというのか。しかしそうであってもDEFUNでもクロージャは作れるだろ。

CL-USER> (let ((z 10))
(defun foo ()
(setf z (1+ z))
(format t "Z: ~d~%" z)))
FOO
CL-USER> (foo)
Z: 11
NIL
CL-USER> (foo)
Z: 12
NIL
CL-USER>

なんぞ。


複数のクロージャが、ひとつのbindingを捕捉することができる。どれ。

CL-USER> (defparameter *fn2*
(let ((count 0))
(list
#'(lambda () (incf count))
#'(lambda () (decf count))
#'(lambda () count))))
*FN2*
CL-USER> (mapcar #'funcall *fn2*)
(1 0 0)
CL-USER> (funcall (car *fn2*))
1
CL-USER> (funcall (car *fn2*))
2
CL-USER> (funcall (car *fn2*))
3
CL-USER> (funcall (car *fn2*))
4
CL-USER> (mapcar #'funcall *fn2*)
(5 4 4)
CL-USER> (funcall (cadr *fn2*))
3
CL-USER>

なるほど。

ここで小休止。
復帰。

Dynamic, a.k.a. Special, Variables


  • global variables を生成するには、DEFVARとDEFPARAMETERがある。
  • scopingのルールは、これらについても他と同じ。だから、LETで、*standard-output*を*some-other-stream*にbindした場合、そのbindingsはLETのbodyのみで有効。
  • DEFVARとDEFPARAMETERは自動的にspecial宣言していると。
  • 思うのだが、top-levelがまさにlexicalになっているMLと比べると、top-levelで名前定義がglobal specialである環境(例えば今やっているCL)とかでは、top-levelでlexicalだdynamicだといってもなんだかわからないものではないのか。



Constants

特になし。


Assignment


  • 関数呼び出しは値渡し



Generalized Assignment


  • SETF は、user-defined places に使えるように拡張可能。DEFSETF、DEFINE-SETF-EXPANDERなどを使うらしい。



Other Ways to Modify Places

特になし。

0 件のコメント: