Schemeプログラムは一連の式、定義、構文定義で構成される。式はsection 5. 式で説明する。この章では定義と構文定義を説明する。
プログラムは概してファイルに保管されるか、実行中のScheme処理系で対話的に入力される。無論これ以外の方法も考えられる。ユーザインタフェースは本報告書の取り扱い範囲外である。(実際Schemeは、機械的な処理系がない場合でも計算法を表現する記法として有効である。)
プログラムのトップレベルで生成される定義と構文定義は、宣言と解釈できる。宣言により、トップレベル環境にバインディングが作成される。あるいはトップレベルの既存のバインディングが変更される。プログラムのトップレベルに書かれた式は必ず解釈され、プログラムが呼び出されるかロードされた時に順次実行される。これは一般に一定の初期化を行なうものである。
プログラムのトップレベルでの(begin <表現形式1> ...)
は、begin
のボディを形成する連続する式、定義、構文定義に等しい。
定義は、必ずというわけではないが、式が許される一定の文脈で有効である。定義は、<プログラム>のトップレベルと<ボディ>の開始点でのみ有効である。
定義は以下の形式の一つで行なわなければならない。
(define <変数> <式>)
(define (<変数> <仮引数群>) <ボディ>)
<仮引数群>はゼロ個以上の変数の連続か、もしくは(ラムダ
式の場合のように)一つ以上の変数の連続に、空白で区切った
ピリオドともう一つの変数を続けたものでなければならない。
この形式は以下に等価である。
(define <変数> (lambda (<仮引数群>) <ボディ>))
(define (<変数> . <仮引数>) <ボディ>)
<仮引数>はただ一つの変数でなければならない。この形式は
以下に等価である(22)。
(define <変数> (lambda <仮引数> <ボディ>))
プログラムのトップレベルにおいて、次の定義
(define <変数> <式>)
は本質的に、<変数>がバインド済みの場合の次の割り当て式と同じ効果がある。
(set!
<変数> <式>)
ただし<変数>がバインドされていない場合は、割り当てを実行する前に定義を行なうことによって、<変数>が新しい記憶域にバインドされる。バインドされていない変数にset!
を実行した場合はエラーになる。
(define add3 (lambda (x) (+ x 3))) (add3 3) => 6 (define first car) (first '(1 2)) => 1
処理系によっては、考えられる変数をすべて記憶域にバインドした初期環境を使用するものがある。その記憶域の大部分に含まれる値は未定義である。そのような処理系の場合、トップレベルの定義はまさしく割り当てに等しい。
<ボディ>の冒頭(すなわちlambda
式、let
式、let*
式、letre
c式、let-syntax
式、letrec-syntax
式のボディ、もしくは適切な形式の定義のボディ)に定義を配置してもよい。このような定義は先に述べたトップレベルの定義に対して、内部での定義と考えられる。内部での定義で定義された変数は、<ボディ>に対して局所的である。すなわち<変数>は割り当てられるのではなくバインドされる。したがってバインディング領域は<ボディ>全体である。次に例を挙げる。
(let ((x 5)) (define foo (lambda (y) (bar x y))) (define bar (lambda (a b) (+ (* a b) a))) (foo (+ x 3))) => 45
内部での定義を含む<ボディ>は、完全に等価なletrec
式に必ず変換できる。例えば上記のlet式は次の式に等価である。
(let ((x 5)) (letrec ((foo (lambda (y) (bar x y))) (bar (lambda (a b) (+ (* a b) a)))) (foo (+ x 3))))
まさに等価なletrec
式の場合と同じく<ボディ>内部での定義の<式>は、定義中のいかなる<変数>への割り当ても参照も行なわずに、一つ一つ評価できなければならない。
内部での定義ができる場所では(begin <定義1> ...)
は常に、begin
式のボディを構成する一連の定義に等価である。
構文定義は、<プログラム>のトップレベルでのみ有効である。構文定義の形式 は次の通りである。
(define-syntax <キーワード> <変換手続き仕様>)
<キーワード>は識別子である。<変換手続き仕様>はsyntax-rules
の発動でなければならない。<キーワード>を指定変換手続きにバインドして、トップレベルの構文環境が拡張される。
内部での定義には、define-syntax
に類似したものは存在しない。
文脈で許される限りはマクロを定義と構文定義に展開できるが、定義や構文定義によるシャドウイングで次のような構文キーワードが隠される場合はエラーである。トップレベルグループでの定義もしくは内部での定義において、シャドウイングを行なう定義を含む定義が事実上定義の一つであるかどうかを判別するのに意味が必要となる構文キーワード。もしくはグループとそれに続く式の境界を判別するのに意味が必要となる構文キーワード。例えば以下はエラーである。
(define define 3) (begin (define begin list)) (let-syntax ((foo (syntax-rules () ((foo (proc args ...) body ...) (define proc (lambda (args ...) body ...)))))) (let ((x 3)) (foo (plus x y) (+ x y)) (define foo x) (plus foo x)))