読者のみなさんは、これまで見てきた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)))