フォームと評価
Schemeシステムにフォーム(データで表現される式)が与えられると,システムはフォームを「評価」して,その値を返す.
変数が評価されると,その変数の値が返される.
> (define x -1) x > x -1関数にその引数を与えて評価すると,まず各引数が評価され,最後に関数の値が返る. 引数が複数あるときの評価の順番は,処理系に依存する.
> (* (+ 1 2) (+ 3 (* 4 5))) ;;(* 3 (+ 3 (* 4 5))) ;;(* 3 (+ 3 20)) ;;(* 3 23) 69define(変数,関数の定義), set!(変数への代入)などは関数の形をしているが,その引数の全てが評価されるとは限らない. 例えば,
> (define x 4) > (set! x 5)において,第一引数にあたる"x"の値は評価されない. この他にこのような特殊なフォームとして,
and or if cond let lambda do quoteなどがある.
リストの第一要素は,常に関数あるいは特殊なフォームとして解釈されるので注意が必要である. 例えば,数値リストを引数として,その要素の総和を返す関数sum-of-listがあったとする. 例えば(1 2 3 4)に対しては,要素の合計10を返して欲しい. ところが,以下のように入力すると,
> (sum-of-list (1 2 3 4)) ==> error: 1 is not a functionとエラーになってしまう.これは,
(sum-of-list (1 2 3 4))という式において引数のリスト(1 2 3 4)が評価される際に,その第一要素の『1』が関数であり,(2 3 4)を引数として呼び出されていると解釈されてしまうためである. これを防ぐには,すぐあとで説明するクォートを用いて引数をそのまま関数に渡すようにする必要がある.
> (sum-of-list (quote (1 2 3 4))) 10
ちなみにsum-of-listは,以下のように定義できる. 詳細については,再帰呼出し,およびリスト処理関数を参照のこと.
(define (sum-of-list l) (if (null? l) 0 (+ (car l) (sum-of-list (cdr l)))))
記号はクォートしない限り,その記号名に対応する変数,関数,あるいは特殊なフォームとして扱われる. システムに定義されていない記号の値を評価するとエラーとなる.
> (define abc 1) abc > abc 1 > + #<function +> > no-such-symbol ==> error : unbound variable: no-such-symbol
クォート
上で挙げたように,quoteは特殊なフォームの一つであり,
(quote データ)は,“データ”をそのまま返す(記号はその印字名で返される).
> (define x 2) x > x 2 > (quote x) x > (quote X) x > (quote (IF (= x 1) Y Z)) (if (= x 1) y z)quoteは頻繁に用いられるため,'(シングルクォート)で省略される. すなわち (quote x) = 'x
> (define y 'x) y > y x > '(a b c) (a b c) > '(+ 1 2 3) (+ 1 2 3) > ''x 'x
シングルクォート'は,バッククォート`と間違いやすいので気をつけること. Schemeでは,バッククォートは特殊なフォームquasiquoteの省略記法として用いられるが,本文書ではquasiquoteは扱わないことにする.
eval
evalは,与えられたデータの値を評価する(evaluate)関数である.
> (eval 100) 100 > (define x '(+ 1 2 3)) x > x (+ 1 2 3) > (eval x) 6 > (define y 'x) y > y x > (eval y) (+ 1 2 3) > (eval (eval y)) 6 > (define z '(1 2 3 4)) y ;; consについては,ここを参照のこと. > (eval (cons '+ z)) ;; (+ 1 2 3 4)を評価する 10 > (eval (cons '* z)) ;; (* 1 2 3 4)を評価する 24
注
多くのScheme処理系では,evalはこのように1引数関数として実装されている. しかし,現在のSchemeの仕様書である 『Revised5Report on the Algorithmic Language Scheme』では, evalが2引数の関数と定義されており,第2引数として環境記述子 (environment-specifier)を与えることになっている.