"Common Lisp: A Gentle Introduction to Symbolic Computation"を読んで自分の理解をまとめていく。
やっとよく見るコードの形で議論が進んでいくようだ。
Contents
EVAL notaition
今まではブロック図表記で考えてきたがEVAL
で評価できる書き方で考えていく。文字で書くと何やら難しいことを言っているようだが、要は(+ 1 2)
はEVAL
で3
と評価されるという話。
自分でコードを書く際はEVAL
と入力する必要はない、基本的には。
(+ 1 2) ; => 3
基本的な評価ルールは、
- 数値、文字列、
T
、NIL
はそれ自身に評価される。 - リストは先頭要素を関数として評価し、残りの要素をその関数の引数とする。
- 引数も評価したうえで関数に渡される。
例えば(+ (+ 1 2) 4)
は引数(+ 1 2)
が3
に評価され、その3
と4
が最初の+
の引数として渡されるということ。 - シンボルはシンボルが指している変数の値へと評価される。
- シンボルやリストを評価せずデータとして扱うためにはquote
'
(シングルクォート)する。
いろいろevalしてみる
+, -, *, /
特に悩むところはなし。引数は左側から評価されていく。
(+ 1 2) ; => 3 (+ 1 2 3 4 5) ; => 15 (- 1 2) ; => -1 (- 1 2 3 4 5) ; => -13 (* 1 2) ; => 2 (* 1 2 3 4 5) ; => 120 (/ 1 2) ; => 1/2 (/ 1 2 3 4 5) ; => 1/120
ABS, SQRT
これも特に悩むところはなし。
SQRT
は返り値は整数ではなく浮動小数点のようだ。負の値を入れても複素数で返してくる。複素数をプログラム中で使う方法はまた後日考えよう。
(abs 100) ; => 100 (abs -100) ; => 100 (sqrt 100) ; => 10.0 (sqrt -100) ; => #C(0.0 10.0)
Predicates
例えばnumberp
。
(numberp 10) ; => T (numberp a) ; => ERROR! (numberp 'a) ; => NIL
先に述べたように引数も評価されてから関数に渡される。2行目のようにa
をクォートしないと評価しようとしてエラーとなる。(まだシンボルa
になにも束縛していないためUNBOUND-VARIABLEとなる。)
ほかのPredicatesも特に悩むところはない。
リストの評価
先に述べたようにリストは基本的には一つ目の要素を関数、残りを引数として評価されてしまう。ただのデータとしてリストを扱うには上でシンボルをクォートしたようにリストもクォートする必要がある。
(a b c d) ; => ERROR! '(a b c d) ; => (A B C D) ('a 'b 'c 'd) ; => ERROR! (list 'a 'b 'c 'd) ; => (A B C D)
1行目はa
というfunctionはないというエラーになる。3行目も'a
というfunctionはないというエラーになる。自分の環境ではvlimeのREPLで'(a b c d)
を上記のようには評価できずエラーとなった。sbclのREPLに打ち込んだ場合は上記通り動いていた。今のところ理由はわからない。
上記を踏まえて(a b c d)から一つ目の要素を取り出す場合は、
(first '(a b c d)) ; => A
のようにクォートする。
まとめ
- 数値、文字列、
T
、NIL
はそれ自身に評価される。 - リストは一つ目の要素を関数、残りを引数として評価される。
- シンボルは束縛されている値、関数に評価される。
- 束縛されていないシンボルを評価しようとするとエラー
- リスト、シンボルを評価せずデータとして渡すためにはクォート
'
する。
補足
"Common Lisp: A Gentle Introduction to Symbolic Computation"ではシンボルに対して束縛(bounded)という言葉を使うのは正しくないと言っているようだ。。束縛されるのはシンボルが参照している変数(variable)だとということなのだろうか。
コメント