読者のみなさんは、これまで見てきたSchemeの例題プログラムも やはりS式であるとに気づくことになるでしょう。このことは 全てのSchemeプログラムに言えることです。プログラムはデータです。
すなわち、文字データ #\c
はプログラムあるいは
フォームです。プログラムというかわりに
フォームというより一般的な言葉をつかいます。
こうすることにより、プログラムの断片もとりあげることが
できます。
Schemeはフォーム#\c
を評価して、値#\c
とします。
これは、#\c
は自己評価的であるからです。すべての
S式が自己評価的であるわけではありません。たとえば、
シンボルのS式xyz
は評価するのと変数xyz
が
保持していた値になります。リストのS式(string->number "16")
は
評価すると数値の16になります。
すべてのS式が正しいプログラムであるとはかぎりません。
ドット対のS式(1 . 2)
をSchemeのリスナーから入力すると
エラーになるでしょう。
Schemeはリストフォームを評価するとき、そのフォームの最初の要素、 先頭を検査します。先頭を評価して手続きでなれば、フォームの のこりの部分を評価して、その引数の値を得たうえで、手続きをその 引数に適用します。
もし、上のフォームの先頭がスペシャルフォームであったら、
評価はそのフォームに特有の方法で進みます。
いくつかのスペシャルフォームはすでに見てきました。
begin
、define
、set!
です。begin
はその
サブフォームを順に評価し、最後のサブフォームの結果の値を
全体の結果のとして返します。define
は変数を導入し、それを
初期化します。set!
は変数の束縛を変更します。
すでに見てきた手続きは、cons
、string->list
などのような
Schemeのプリミティブな手続きでした。ユーザはスペシャルフォーム
lambda
をつかって、独自の手続きをつくりだすことができます。
たとえば、次のものは、引数に2
を加える手続きを定義しています。
(lambda (x) (+ x 2))
最初のサブフォーム、(x)
はパラメータのリストです。
のこりのサブフォームは手続きの本体を構成するものです。
この手続きは一つの引数に対して呼ぶことができ、プリミティブ
手続きと同じように振舞います。
((lambda (x) (+ x 2)) 5) => 7
もし、この同じ手続きを何度も呼びたければ、lambda
の複製を
そのたびに呼んでもいいのですが、もっとよい方法があります。
この手続きの値を保持する変数を使うことができます。
(define add2 (lambda (x) (+ x 2)))
こうすると、この変数add2
を引数に2を足す必要があるたびに
呼びだすことができます。
(add2 4) => 6 (add2 9) => 11
lambda
手続きのパラメータは最初のサブフォーム(先頭、シンボル
lambda
の直後)で指定します。add2
は単一引数(単項)手続き
なのでパラメータリストはシングルトンリスト(x)
です。シンボルx
は
手続き引数を保持する変数として振舞います。変数x
は手続き本体について
局所的(ローカル)であるといいます。
2引数手続きについては2要素リストを使うことができます。 一般にn引数手続きについてはn要素リストを使えます。 次の例は長方形の面積を計算する2引数手続きです。 ふたつの引数は長方形のたてとよこです。
(define area (lambda (length breadth) (* length breadth)))
area
はその引数をかけあわせていますので、プリミティブ手続き
*
と同じです。単に
(define area *)
と書いてもよかったわけです。
手続きのなかにはときに異った数の引数をとるものがあります。
このようにするためにはlambda
パラメータリストを単一の
シンボルに置き換えます。このシンボルはその手続きが呼ばれる
引数のリストとして振舞います。
一般的には、このlambda
パラメータリストは(x ...)
という
フォームあるいは、単一のシンボルまたはドット対(x ... . z)
という
フォームです。ドット対の場合、ドットの前のすべての変数は
手続き呼び出しで、対応するすべての引数に束縛され、ドットの
後の一個の変数は、のこりのすべての引数をひとつのリストに
拾いあげます。
apply
Scheme手続きapply
は手続きを引数のリストに適用します。
(define x '(1 2 3)) (apply + x) => 6
一般には、apply
は、ひとつの手続きと、別に可変長の引数をとります。
この引数の最後はリストでなければなりません。最後の引数の前に間の引数
を付けて引数リストをつくります。そうして、この引数リストに対して、
手続きを呼んで、その結果を返します。
(apply + 1 2 3 x) => 12
スペシャルフォームbegin
を使って、順番に評価する必要のある一連の
サブフォームをひとつにまとめます。
(define display3 (lambda (arg1 arg2 arg3) (begin (display arg1) (display " ") (display arg2) (display " ") (display arg3) (newline))))
Schemeでは、lambda
-本体は暗黙のbegin
です。したがって、
display3
の本体のbegin
はなくてもかまいません。しかし、
あって困るものでもありません。display3
はもっと単純になります。
(define display3 (lambda (arg1 arg2 arg3) (display arg1) (display " ") (display arg2) (display " ") (display arg3) (newline)))