アルゴリズム言語 Scheme 報告書 四訂版
(Revised(4) Report on the Algorithmic Language Scheme)

William Clinger & Jonathan Rees (編集)

     H. Abelson      R. K. Dybvig    C. T. Haynes    G. J. Rozas
     N. I. Adams IV  D. P. Friedman  E. Kohlbecker   G. L. Steele Jr.
     D. H. Bartley   R. Halstead     D. Oxley        G. J. Sussman
     G. Brooks       C. Hanson       K. M. Pitman    M. Wand

ALGOL 60 のみたまにささぐ

     TeXinfo 化   A. Jaffer (jaffer@ai.mit.edu)
     日本語訳   H. Suzuki (suzuki@acm.org)

我々は，この報告書を Scheme コミュニティ全体に属するものとしようと思う。そのため我々は，これの全部または一部を無料で複写することを許可する。とりわけ我々は，Scheme の実装者がこの報告書をマニュアルその他の文書のための出発点として，必要に応じて改変しつつ，利用することを奨励する。

(原文: We intend this report to belong to the entire Scheme community, and so we grant permission to copy it in whole or in part without fee.  In particular, we encourage implementors of Scheme to use this report as a starting point for manuals and other documentation, modifying it as necessary. )

1991 年 11 月 2 日

Summary
*******

本報告書はプログラミング言語 Scheme を定義する一つの記述を与える。 Scheme は，静的スコープをもち，真正の末尾再帰をする Lisp プログラミング言語の一方言であり， Guy Lewis Steele Jr. と Gerald Jay Sussman によって発明された。 Scheme は，並外れて明快で単純な意味論をもち，式をつくる方法の種類がごく少数になるように設計された。命令型，関数型，メッセージ渡しの各スタイルを含む広い範囲のプログラミング・パラダイムが Scheme により手軽に表現できる。

序章は本言語と本報告書の簡単な歴史を述べる。

最初の三つの章は，本言語の基本的なアイディアを提示するとともに，本言語を記述するため及び本言語でプログラムを書くために用いられる記法上の規約を記述する。

ExpressionsとProgram structureは式，プログラム，定義の構文と意味論を記述する。

Standard proceduresは Scheme の組込み手続きを記述する。これには本言語のデータ操作と入出力プリミティブのすべてが含まれる。

Formal syntax and semanticsは，拡張 BNF で書かれた Scheme の形式的構文を形式的な表示的意味論とともに定める。形式的な構文と意味論の後には言語の使用例が続く。

付録は Scheme の構文を拡張するために使われ得るマクロ機能を記述する。

報告書の最後は参考文献とアルファベット順の索引である。

はじめに
****

歴史
==

プログラミング言語の設計は，機能の上に機能を積み重ねることによってではなく，余分な機能が必要であるように思わせている弱点と制限を取り除くことによってなされるべきである。式をつくるための規則が少数しかなくても，その組み合わせ方法に全く制限がなければ，今日使われている主要なプログラミング・パラダイムのほとんどをサポートするのに十分なだけの柔軟性を備えた実用的で効率的なプログラミング言語を満足につくり上げられることを，Scheme は証明している。

Scheme は，λ計算におけるのと同様なファースト・クラスの手続きをとり入れた初めてのプログラミング言語の一つであった。そしてそれにより，動的に型付けされる言語における静的なスコープ規則とブロック構造の有用性を証明した。 Scheme は，手続きをλ式とシンボルから区別し，すべての変数に対し単一の字句的環境を使用し，手続き呼出しの演算子の位置をオペランドの位置と同じように評価する初めての主要な Lisp 方言であった。全面的に手続き呼出しによって繰返しを表現することで Scheme は，末尾再帰の手続き呼出しが本質的には引数付き goto であるという事実を強調した。 Scheme は，すべての既知の逐次的制御構造を合成できるファースト・クラスの脱出手続きを組み込んだプログラミング言語のうち，初めて広く使われた言語であった。最近になって Scheme は，Common Lisp の総称的算術演算の設計に基づいて，正確数と不正確数の概念を導入した。この報告書の付録をもって Scheme は，ブロック構造をもった言語の構文を安全に拡張することを可能にする保健的なマクロをサポートした初めてのプログラミング言語になる。 (訳注：「保健的」は hygienic の訳。この語は「衛生的」と訳されることが多いが，ここでは，マクロ展開時の名前の衝突を自動的に回避することによって，展開の健全さを保つことを言い表すために使われているから，この訳語を採った。)

背景
==

Scheme の最初の記述は 1975 年に書かれた [SCHEME75]。改訂報告書は 1978 年に現れた [SCHEME78]。改訂版報告書は， MIT の実装が革新的なコンパイラ [RABBIT] をサポートするためにアップグレードされたのと並行して，その言語の進化を記述した。 1981 年と 1982 年には三つの異なったプロジェクトが MIT，Yale および Indiana 大学で講座に Scheme 類を用いるために始まった [REES82] [MITSCHEME] [SCHEME311]。 Scheme を使用した計算機科学入門の教科書が 1984 年に出版された [SICP]。

Scheme が広まるにつれ，ローカルな方言が分かれはじめ，学生や研究者が他のサイトで書かれたコードの理解にしばしば困難をおぼえるまでになってきた。そこで，Scheme のより良い，より広く受け入れられる標準に向けて作業するため， Scheme の主要な実装の代表者 15 人が 1984 年 10 月に会合した。

その報告書 [RRRS] は 1985 年の夏に MIT と Indiana 大学で出版された。さらにもう一回の改訂が 1986 年の春に行われた [R3RS]。現在の報告書は，1988 年 ACM Conference on Lisp and Functional Programming に先だって開かれた会合と，それに引き続く電子メールにおいて合意された，さらなる改訂事項を反映している。

我々は，この報告書を Scheme コミュニティ全体に属するものとしようと思う。そのため我々は，これの全部または一部を無料で複写することを許可する。とりわけ我々は，Scheme の実装者がこの報告書をマニュアルその他の文書のための出発点として，必要に応じて改変しつつ，利用することを奨励する。

謝辞
==

次の人々の協力に感謝します:  Alan Bawden, Michael Blair, George Carrette, Andy Cromarty, Pavel Curtis, Jeff Dalton, Olivier Danvy, Ken Dickey, Andy Freeman, Richard Gabriel, Yekta Gürsel, Ken Haase, Robert Hieb, Paul Hudak, Richard Kelsey, Morry Katz, Chris Lindblad, Mark Meyer, Jim Miller, Jim Philbin, John Ramsdell, Mike Shaff, Jonathan Shapiro, Julie Sussman, Perry Wagle, Daniel Weise, Henry Wu, Ozan Yigit。我々は Scheme 311 version 4 参照マニュアルからの文章を利用する許可をいただいたことに対して Carol Fessenden, Daniel Friedman,Christopher Haynes に感謝します。 TI Scheme Language Reference Manual からの文章を利用する許可をいただいたことに対して Texas Instruments, Inc. に感謝します。我々は MIT Scheme，T，Scheme 84，Common Lisp，Algol 60 の各マニュアルからの影響を喜んで認めます。

我々はまたこの報告書を TeX で組むために払った多大な努力に対して Betty Dexter に，そして彼女の苦労の元となったそのプログラムを設計したことに対して Donald Knuth に感謝します。

Massachusetts Institute of Technology 人工知能研究所， Indiana 大学 計算機科学科，Oregon 大学 計算機及び情報科学科は，この報告書の準備をサポートしました。 MIT の作業に対するサポートの一部は国防省 Advanced Research Projects Agency によって海軍研究局 契約 N00014-80-C-0505 のもとで与えられました。 Indiana 大学に対するサポートは NFS グラント NCS 83-04567，NCS 83-03325 によって与えられました。

言語の記述
*****

Schemeの概観
*********

意味論
===

この節は Scheme の意味論の概観を与える。詳細な非形式的意味論はBasic conceptsから Standard proceduresで論ずる。参照用にFormal semanticsは Scheme の形式的な意味論を定める。

Algol にならい，Scheme は静的スコープをもつプログラミング言語である。ある変数のそれぞれの使用は，その変数の字句的に明白な束縛と結合される。

Scheme は，顕在的ではなく潜在的な型をもつ。型は変数とではなく値と結合される (値はオブジェクトとも呼ばれる)。 (著者によっては潜在的な型をもつ言語のことを，弱く型付けされた言語，または動的に型付けされる言語と呼ぶことがある)。潜在的な型をもつ言語には他に APL，Snobol および他の Lisp 方言がある。顕在的な型をもつ言語 (強く型付けされた言語，または静的に型付けされた言語といわれることもある) には Algol 60，Pacal, C がある。

Scheme の計算の途上で造られたオブジェクトは，手続きと継続を含め，すべて無期限の寿命をもつ。どの Scheme オブジェクトも決して消滅させられない。ただし実装は，もしあるオブジェクトが将来のいかなる計算にも関係し得ないことを証明できるならば，そのオブジェクトが占める記憶領域を再利用することが許されている。これが，Scheme の実装が (たいていの場合には!) 記憶領域を使い果たさない理由である。大多数のオブジェクトが無期限の寿命をもつ言語には他に APL や他の Lisp 方言がある。

Scheme の実装は，真正に末尾再帰的であることが要求されている。これは，たとえ繰返し計算が構文的には再帰的手続きで記述されているときでも，定数空間でその繰返し計算を実行することを許す。このように末尾再帰的な実装では，繰返しは通常の手続き呼出しメカニズムを使って表現できるから，特別な繰返しコンストラクトはただシンタックス・シュガーとして有用であるにすぎない。

Scheme 手続きはそれ自身オブジェクトである。手続きは動的に造られ，データ構造のなかに格納され，手続きの結果として返される等々。これらの性質をもつ言語には他に Common Lisp や ML がある。

Scheme の一つの特長は，継続もまた``ファースト・クラス''の地位をもつことである。他の大多数の言語では，継続はただ舞台裏で暗躍するにすぎない。継続は非局所的脱出，バックトラック，コルーチンなど広範囲の高度な制御構造を実装することに有用である。Control featuresを見よ。

Scheme 手続きへの引数はつねに値によって渡される。これは，その手続きが実引数の評価結果を必要とするかどうかにかかわりなく，手続きが制御を得る前に実引数の式が評価されることを意味する。 ML，C，APL は，つねに値によって引数を渡す他の三つの言語である。これは Haskell の遅延評価の意味論とも，Algol 60 の名前呼びの意味論とも異なる。それらは，手続きが値を必要としない限り，引数式を評価しない。

Scheme の算術モデルは，計算機内部での数の特定の表現方法からできる限り独立であるように設計されている。 Scheme では，あらゆる整数は有理数であり，あらゆる有理数は実数であり，あらゆる実数は複素数である。したがって，多くのプログラミング言語にとって重要な，整数と実数の算術の違いは， Scheme には現れない。そのかわり，数学的な理想に対応する正確数の算術と，近似に基づく不正確数の算術との違いがある。 Common Lisp と同じく，正確算術は整数に限られてはいない。

構文
==

Scheme は，Lisp の大多数の方言と同じく，プログラムと (それ以外の) データを表すために，カッコに満ちた前置記法を使用する。 Scheme の文法は，データを表すために使われる言語の，部分言語を生成する。この単純で一様な表現の一つの重要な帰結は，他の Scheme プログラムによる取扱いを，Scheme のプログラムに対してもデータに対しても一様化できることである。

read 手続きは，それが読むデータの字句解析だけでなく構文解析も行う。 read 手続きは，その入力をプログラムとしてではなくデータとしてパースする (External representations)。

Scheme の形式的な構文はFormal syntaxで記述される。

記法と用語
=====

必須機能と必須でない機能
------------

Scheme のどの実装も，必須 (essential) であると記された機能をサポートすることが要求されている。明示的に必須と記されていない機能は，必須ではない。実装は自由に，必須でない Scheme の機能を省くこと，または拡張を追加することができる。ただし，その拡張がここで報告される言語と衝突してはならない。とりわけ実装は，この報告書の字句規約をなにも横取りせずかつIdentifiersに構文キーワードとしてリストされた識別子以外なにも予約語としない構文モードを用意することによって，ポータブルなコードをサポートしなければならない。

エラー状況と未規定の振舞
------------

エラー状態について言うとき，この報告書は ``エラーが通知される'' という表現を使って，実装がそのエラーを検出し報告しなければならないことを示す。もしあるエラーの議論にそのような言い回しが現れないならば，実装によるそのエラーの検出または報告は，奨励はされるが要求はされない。実装による検出が要求されないエラー状態は，普通ただ単に ``エラー'' と呼ばれる。

たとえば，ある手続きにその手続きで処理することが明示的に規定されていない引数を渡すことは，たとえそのような定義域エラーがこの報告書でほとんど言及されていなくても，エラーである。実装は，そのような引数を含めるように手続きの定義域を拡張してもよい。

この報告書は ``実装制限の違反を報告してもよい'' という表現を使って，実装の課すなんらかの制限のせいで，ある正当なプログラムを実行し続けられない，と報告することが実装にとって許される状況を示す。実装の制限自体はもちろん奨励されないが，実装が実装制限の違反を報告することは奨励される。

たとえば実装は，あるプログラムを走らせるだけの十分な記憶領域がないとき，実装制限の違反を報告してもよい。

もしある式の値が ``未規定'' (unspecified) であると述べられているならば，その式は，エラーが通知されることなく，なんらかのオブジェクトへと評価されなければならない。ただし，その値は実装に依存する。この報告書は，どんな値が返されるべきかを明示的には述べない。

エントリの書式
-------

ExpressionsとStandard proceduresはエントリごとにまとめられている。各エントリは一つの言語機能または関連する複数の機能の１グループを記述する。ここで一つの機能とは，一つの構文コンストラクトまたは一つの組込み手続きである。エントリは下記の書式の１行以上の見出しで始まる。

 -- 必須 CATEGORY: template
     (その機能が必須である場合)

 -- CATEGORY: template
     (その機能が必須でない場合)

もし CATEGORYが ``構文'' ならば，そのエントリは一つの式型を記述し，見出し行はその式型の構文を与える。式の構成要素は，<式>，<変数> のように山形カッコを使って書かれた構文変数によって示される。構文変数はプログラム・テキストのそれぞれの部分を表すものと考えればよい。たとえば <式> は，構文的に妥当な一つの式である任意の文字の列を表す。記法

     <なにか 1> ...

は <なにか> の０個以上の出現を示し，

     <なにか 1> <なにか 2> ...

は <なにか> の１個以上の出現を示す。

もし CATEGORY が ``手続き'' ならば，そのエントリは一つの手続きを記述し，見出し行はその手続きの呼出しを表すテンプレートを与える。テンプレートのなかの引数名は ITALIC 体で書かれる。したがって，見出し行

 -- 必須 手続き: vector-ref vector k

は必須組込み手続き vector-ref が２引数，ベクタ VECTOR と正確非負整数 K，をとることを示す(下記参照)。見出し行

 -- 必須 手続き: make-vector k
 -- 手続き: make-vector k fill

は，すべての実装において make-vector 手続きが１引数をとるように定義されなければならないこと，そして実装によっては２引数をとるように拡張されるだろうということを示す。

ある演算に対し，処理するとは規定されていない引数を与えることは，エラーである。簡潔のため我々は，もし引数名がDisjointness of typesに挙げられている型の名前でもあるならばその引数はその名前が示す型でなくてはならない，という規約に従う。たとえば上記の vector-ref の見出し行は，vector-ref の第１引数がベクタでなければならないことを命じている。以下の命名規約もまた型の制約を意味する。

  * OBJ 任意のオブジェクト

  * LIST, LIST1, ...LISTJ, ...	リスト (Pairs and lists参照)

  * Z, Z1, ...ZJ, ...	複素数

  * X, X1, ...XJ, ...	実数

  * Y, Y1, ...YJ, ...	実数

  * Q, Q1, ...QJ, ...	有理数

  * N, N1, ...NJ, ...	整数

  * K, K1, ...KJ, ...	正確非負整数

評価の例
----

プログラム例で使われる記号 ``=>'' は ``へと評価される'' と読まれるものとする。たとえば，

     (* 5 8)                     =>  40

は，式 (* 5 8) がオブジェクト 40 へと評価されることを意味する。つまり，より正確には，文字の列 ``(* 5 8)'' によって与えられた式が，文字の列 ``40'' によって外部的に表現され得るあるオブジェクトへと，初期環境のなかで評価される。オブジェクトの外部表現の議論についてはExternal representationsを見よ。

命名規約
----

規約により，つねにブーリアン値を返す手続きの名前は普通 ``?'' で終わる。このような手続きは述語 (predicate) と呼ばれる。

規約により，以前に割り付けられた場所の中へ値を格納する手続き (Storage model参照) の名前は普通 ``!'' で終わる。このような手続きは変易手続き (mutation procedure) と呼ばれる。規約により，変易手続きが返す値は未規定である。

規約により，``->'' は，ある型のオブジェクトをとって別の型の相当するオブジェクトを返す手続きの名前の途中に現れる。たとえば list->vector は，一つのリストをとり，そのリストと同じ要素からなるベクタを返す。

字句規約
****

この節は Scheme プログラムを書くときに使われる字句的な規約のいくつかを非形式的に説明する。 Scheme の形式的な構文についてはFormal syntaxを見よ。

英字の大文字と小文字は，文字定数と文字列定数のなかを除いて，決して区別されない。たとえば Foo は FOO と同じ識別子であり， #x1AB は #X1ab と同じ数である。

識別子
===

他のプログラミング言語で許される大多数の識別子は Scheme にも受理される。識別子をつくる詳細な規則は Scheme の実装によって異なる。しかし，どの実装においても，英字と数字と``拡張アルファベット文字''からなる一つの列であって，数の先頭になり得ない文字で始まるものは，一つの識別子である。さらに + と - と ... も識別子である。下記は識別子の例である。

     lambda                   q
     list->vector             soup
     +                        V17a
     <=?                      a34kTMNs
     the-word-recursion-has-many-meanings

拡張アルファベット文字は，識別子内であたかも英字であるかのように使ってもよい。以下は拡張アルファベット文字である。

     + - . * / < = > ! ? : $ % _ & ~ ^

識別子の形式的な構文についてはLexical structureを見よ。

識別子は Scheme プログラムのなかでいくつかの用途をもつ。

  * ある識別子は構文キーワードとしての用途に予約されている(下記参照)。

  * 構文キーワードでない識別子はどれも変数として使ってよい (Variables and regions参照)。

  * 識別子が一つのリテラルとして若しくは一つのリテラルのなかに現れたとき (Literal expressions参照)，その識別子はシンボルを表示するために使われている(Symbols参照)。

以下の識別子は構文キーワードであり，変数として使われるべきではない。

     =>           do            or
     and          else          quasiquote
     begin        if            quote
     case         lambda        set!
     cond         let           unquote
     define       let*          unquote-splicing
     delay        letrec

いくつかの実装は，構文キーワードも含め，すべての識別子を変数として使うことを許す。これは言語に対する互換性のある拡張である。しかし，制限が緩和されたときには言語にあいまいさがもたらされ，そしてこれらのあいまいさを解決する方法は実装ごとに異なる。

空白と注釈
=====

空白文字 (whitespace character) は，スペースと改行である。 (実装は典型的にはタブや改ページなど付加的な空白文字を定める)。空白は，可読性を改善するために使われ，そしてトークンどうしを分離するために欠かせないものとして使われるが，それ以外の意味はない。ここでトークンとは，識別子や数のような，ある分割できない字句単位である。空白はどの二つのトークンのあいだに出現してもよいが，一つのトークンの途中に出現してはならない。空白は文字列の内部に出現してもよく，そこでは空白は無視されない。

セミコロン (;) は注釈 (comment) の開始を示す。注釈はそのセミコロンが現れた行の行末まで続く。注釈は Scheme にとって不可視だが，その行末は空白として可視である。したがって，注釈は一つの識別子や数の途中に現れることはできない。

     ;;; FACT 手続き
     ;;; 非負整数の階乗 (factorial) を計算する
     (define fact
       (lambda (n)
         (if (= n 0)
             1        ;再帰の底: 1 を返す
             (* n (fact (- n 1))))))

その他の記法
======

数を表すために使われる記法の記述についてはNumbersを見よ。

. + -
     これらは数で使われ，そしてまた最初の文字を除き識別子のどこにでも出現できる。１個の孤立した正符号または負符号もまた識別子である。１個の孤立した (数や識別子のなかに出現するのではない) ピリオドは，ペアの表記 (Pairs and lists) と，仮パラメタ並びの残余パラメタ (Lambda expressions) を示すために使われる。３個の連続したピリオドの孤立した列もまた識別子である。

( )
     丸カッコはグループ化とリストの表記のために使われる(Pairs and lists)。

'
     単一引用符はリテラル・データを示すために使われる(Literal expressions)。

`
     逆引用符は準定数データを示すために使われる(Quasiquotation)。

, ,@
     文字 コンマ と列 コンマ アットマーク は逆引用符と組み合わせて使われる (Quasiquotation)。

"
     二重引用符は文字列を区切るために使われる(Strings)。

\
     逆スラッシュは文字定数を表す構文で使われ(Characters)，そして文字列定数のなかのエスケープ文字として使われる(Strings)。

[ ] { }
     左右の角カッコと波カッコは言語の将来あり得る拡張のために予約されている。

#
     シャープ記号は，以下のように，その直後に続く文字によって様々な目的に使われる。

#t #f
     これらはブーリアン定数である(Booleans)。

#\
     これは文字定数の先頭となる(Characters)。

#(
     これはベクタ定数の先頭となる(Vectors)。ベクタ定数は ) を末尾とする。

#e #i #b #o #d #x
     これらは数の表記に使われる(Syntax of numerical constants)。

基本概念
****

変数と領域
=====

構文キーワードでないどんな識別子も変数として使ってよい (Identifiers参照)。変数は，一つの値を格納可能な一つの場所の名前になることができる。そうしている変数は，その場所に束縛されている (be bound) と言われる。プログラム内のある点において有効なすべての可視な束縛からなる集合は，その点において有効な環境 (environment) として知られる。変数が束縛されている場所に格納されている値は，その変数の値と呼ばれる。用語の誤用によって，変数が値の名前になるとか，値に束縛されるとか言われることがある。これは必ずしも正確ではないが，こうした用法から混乱がもたらされることは滅多にない。

ある種の式型は，新しい場所を造って変数をその場所に束縛するために使われる。これらの束縛コンストラクト (binding construct) のうち最も基本的なものはλ式である。なぜなら，他の束縛コンストラクトはすべてλ式を使って説明できるからである。他の束縛コンストラクトは let, let*, letrec および do の各式である (Lambda expressions, Binding constructs, Iteration参照)。

Algol および Pascal と同じく，そして Common Lisp を除く他の大多数の Lisp の方言とは異なり，Scheme はブロック構造による静的なスコープをもつ言語である。変数がプログラムで束縛されるところにはそれぞれ，その束縛が有効であるプログラム・テキストの領域 (region) がおのおの存在する。領域は，その束縛を設けた当の束縛コンストラクトによって決定される。たとえば，もし束縛がλ式によって設けられたならば，その束縛の領域はそのλ式全体である。変数の参照または代入はそれぞれ，その変数の束縛のうち，その使用を内部にもつ最内の領域を設けた束縛を参照する。もしその使用を内部にもつような領域をとるその変数の束縛がない場合，その使用はトップ・レベル環境でのその変数の束縛を，もしあれば，参照する (Standard procedures参照)。もしもその識別子に対して全く束縛がないならば，その識別子は未束縛である (be unbound) と言われる。

真と偽
===

どんな Scheme 値も，条件テストのためのブーリアン値として使うことができる。 Booleansで説明するように， #f を除くすべての値は，そのようなテストにおいて真とみなされる。この報告書は ``真'' (true) という言葉を，なんであれ真とみなされる Scheme 値を言い表すために使い，``偽'' (false) という言葉を #f を言い表すために使う。

注：  実装によっては，空リストもまた真ではなく偽とみなされる。

外部表現
====

Scheme (と Lisp) の重要な概念に，文字の列としてのオブジェクトの外部表現 (external representation) という概念がある。たとえば整数 28 の外部表現は文字の列 ``28'' であり，整数 8 と 13 からなるリストの外部表現は文字の列 ``(8 13)'' である。

オブジェクトの外部表現は必ずしも一意的ではない。整数 28 には ``#e28.000'' や ``#x1c'' という表現もあり，さきの段落のリストには ``( 08 13 )'' や ``((8 . (13 . ()))'' という表現もある (Pairs and lists参照)。

多くのオブジェクトには標準的な外部表現があるが，手続きなど標準的な表現がないオブジェクトもある (ただし，実装によってはそれらに対する表現を定義しているかもしれない)。

外部表現をプログラムのなかに書いて，対応するオブジェクトを得ることができる (quote, Literal expressions参照)。

外部表現を入出力のために使うこともできる。手続き read (Input) は外部表現をパースし，手続き write (Output) は外部表現を生成する。これらは共になってエレガントで強力な入出力機能を与えている。

文字の列 ``(+ 2 6)'' は，整数 8 へと評価される式ではあるが，整数 8 の外部表現ではないことに注意せよ。むしろ，それはシンボル + と整数 2, 6 からなる３要素のリストの外部表現である。 Scheme の構文には，なんであれ一つの式であるような文字の列は，なんらかのオブジェクトの外部表現でもある，という性質がある。これは混乱をもたらしかねない。なぜなら，与えられた文字の列が意味するものがデータなのかプログラムなのか，文脈から離れては必ずしも明らかではないからである。しかし，これは強力さの源でもある。なぜなら，これはインタープリタやコンパイラなど，プログラムをデータとして (あるいは逆にデータをプログラムとして) 扱うプログラムを書くことを容易にするからである。

様々な種類のオブジェクトの外部表現の構文は，そのオブジェクトを取扱うためのプリミティブの，Standard proceduresの該当する節における記述に付随して述べられる。

型の分離性
=====

どのオブジェクトも次の述語を二つ以上満たすことはない。

     boolean?          pair?
     symbol?           number?
     char?             string?
     vector?           procedure?

これらの述語が ブーリアン，ペア，シンボル，数，文字，文字列，ベクタ，手続き の各型を定義する。

記憶モデル
=====

変数およびペアやベクタや文字列のようなオブジェクトは，暗黙のうちに場所ないし場所の列を指し示している。たとえば文字列は，その文字列にある文字数と同じだけの場所を指し示している。 (これらの場所は必ずしもマシンの１語長にそのまま対応するとは限らない)。新しい値をこれらの場所の一つに string-set! 手続きを使って格納したとしても，文字列は依然として以前と同じ場所を指し続ける。

変数参照または car，vector-ref，string-ref などの手続きによって，ある場所から取り出されたオブジェクトは，取り出す前にその場所に最後に格納されたオブジェクトと，eqv? (Equivalence predicates) の意味で等価である。

場所にはそれぞれ，その場所が使用中かどうかを示すマークが付けられている。未使用の場所を変数またはオブジェクトが参照することは決してない。記憶領域が変数またはオブジェクトのために割り付けられる，とこの報告書が述べるとき常にそれが意味することは，未使用の場所からなる集合から適切な個数の場所が選んで取り出され，そして取り出された場所にそれらが今や使用中であるということを示すマークが付けられてから，変数またはオブジェクトがそれらを指し示すようにされる，ということである。

多くのシステムでは，定数 (つまりリテラル式の値) を読出し専用メモリに置くことが望ましい。これを表現するため，場所を指し示す各オブジェクトにそのオブジェクトが可易 (mutable) か不易 (immutable) かを示すフラグが付けられていると想像すると便利である。このとき定数および symbol->string が返す文字列は不易オブジェクトである。これに対し，この報告書に挙げられている他の手続きによって造られるオブジェクトはすべて可易である。不易オブジェクトが指し示す場所に新しい値を格納しようとすることはエラーである。

式
*

Scheme の式は，変数参照，リテラル，手続き呼出し，条件式など，一つの値を返すコンストラクトである。

式型は原始式型 (primitive expression type) と派生式型 (derived expression type) に大別される。原始式型は変数と手続き呼出しを含む。派生式型は意味論的に原始的ではなく，むしろFormal derived expression typesのように原始コンストラクトに翻訳して説明され得る。派生式型は，言葉の厳密な意味において冗長であるが，一般的な利用法のパターンをとらえており，それゆえ便利な略記法として用意されている。

原始式型
====

変数参照
----

 -- 必須 構文: <変数>

     一つの変数 (Variables and regions) からなる式は，変数参照である。変数参照の値は，その変数が束縛されている場所に格納されている値である。未束縛の変数を参照することはエラーである。

          (define x 28)
          x                           =>  28

リテラル式
-----

 -- 必須 構文: quote <データ>
 -- 必須 構文: '<データ>
 -- 必須 構文: <定数>

     (quote <データ>) は <データ> へと評価される。 <データ> は Scheme オブジェクトの外部表現ならなんでもよい (External representations参照)。この記法はリテラル定数を Scheme コードの中に含めるために使われる。

          (quote a)                   =>  a
          (quote #(a b c))            =>  #(a b c)
          (quote (+ 1 2))             =>  (+ 1 2)

     (quote <データ>) は '<データ> と略記してもよい。この二つの記法はすべての点で等価である。

          'a                          =>  a
          '#(a b c)                   =>  #(a b c)
          '()                         =>  ()
          '(+ 1 2)                    =>  (+ 1 2)
          '(quote a)                  =>  (quote a)
          ''a                         =>  (quote a)

     数値定数，文字列定数，文字定数，ブーリアン定数は ``それ自身へと'' 評価される。したがって，それらはクォート (quote) しなくてもよい。

          '"abc"                      =>  "abc"
          "abc"                       =>  "abc"
          '145932                     =>  145932
          145932                      =>  145932
          '#t                         =>  #t
          #t                          =>  #t

     Storage modelで注意したように， set-car! や string-set! のような変易手続きを使って定数 (つまりリテラル式の値) を変えることはエラーである。

手続き呼出し
------

 -- 必須 構文: <演算子> <オペランド 1> ...

     手続き呼出しは，呼び出される手続きとしての式と，それに渡される引数としての各式を，単純に丸カッコでくくることによって書かれる。演算子とオペランドの各式が (未規定の順序で) 評価され，そしてその結果の手続きへその結果の引数が渡される。

          (+ 3 4)                     =>  7
          ((if #f + *) 3 4)           =>  12

     数多くの手続きが，変数の値として初期環境で利用可能である。たとえば，上の例の加算と乗算の手続きは変数 + と * の値である。新しい手続きはλ式を評価することによって造られる (Lambda expressions参照)。

     手続き呼出しはコンビネーションとも呼ばれる。

     注：  ほかの Lisp の方言とは対照的に，評価の順序は未規定であり，そして演算子式とオペランド式はつねに同じ評価規則で評価される。

     注：  演算子とオペランドの各式がどのように同時的に評価されるとしても，その効果はなんらかの逐次的な評価順序と一致しなくてはならない。それ以外，評価の順序は未規定である。評価の順序は，各手続き呼出しごとに異なって選択されてもよい。

     注：  多くの Lisp の方言では，空のコンビネーション () は正当な式である。 Scheme では，コンビネーションは少なくとも１個の部分式をもたなければならないから，() は構文的に妥当な式ではない。

λ式
--

 -- 必須 構文: lambda <仮引数部> <本体>

     構文：  <仮引数部> は後述するような仮引数並びとする。 <本体> は１個以上の式からなる列とする。

     意味： λ式は手続きへと評価される。 λ式が評価されたとき有効だった環境は，その手続きの一部として記憶される。その手続きを後からなんらかの実引数とともに呼び出すと， λ式が評価されたときの環境が，仮引数並びの変数の新しい場所への束縛によって拡張され，対応する実引数値がその場所へ格納される。そしてλ式の本体の各式が，その拡張された環境において逐次的に評価される。本体の最後の式の結果が，その手続き呼出しの結果として返される。

          (lambda (x) (+ x x))        =>  一つの手続き
          ((lambda (x) (+ x x)) 4)    =>  8

          (define reverse-subtract
            (lambda (x y) (- y x)))
          (reverse-subtract 7 10)     =>  3

          (define add4
            (let ((x 4))
              (lambda (y) (+ x y))))
          (add4 6)                    =>  10

     <仮引数部> は次の形式のうちの一つとする。

       * (<変数 1> ...): 手続きは固定個数の引数をとる。手続き呼出しのとき，引数は対応する変数の束縛に格納される。

       * <変数>: 手続きは任意個数の引数をとる。手続き呼出しのとき，実引数の列が１個の新しく割り付けられたリストへと変換され，そしてそのリストが <変数> の束縛に格納される。

       * (<変数 1> ... <変数 n-1> . <変数 n>): もしスペースで区切られたピリオドが最後の変数の前にあるならば，まずそれ以外の仮引数に対して実引数がすべて対応づけられる。そして，残った実引数からなる新しく割り付けられたリストが，最後の変数の束縛に格納される値となる。

     一つの <変数> が <仮引数部> のなかに複数回現れることはエラーである。

          ((lambda x x) 3 4 5 6)      =>  (3 4 5 6)
          ((lambda (x y . z) z)
           3 4 5 6)                   =>  (5 6)

     eqv? と eq? が手続きについて機能できるようにするため， λ式の評価結果として造られた手続きはそれぞれ記憶場所でタグ付けされる (Equivalence predicates参照)。

条件式
---

 -- 必須 構文: if <テスト> <帰結部> <代替部>
 -- 構文: if <テスト> <帰結部>

     構文：  <テスト>，<帰結部>，<代替部> はどんな式でもよい。

     意味：  if 式は次のように評価される。まず，<テスト> が評価される。もしそれが真値 (Booleans参照) をもたらすならば， <帰結部> が評価されてその値が返される。そうでなければ，<代替部> が評価されてその値が返される。 <テスト> が偽値をもたらし，そして <代替部> がないとき，式の結果は未規定である。

          (if (> 3 2) 'yes 'no)       =>  yes
          (if (> 2 3) 'yes 'no)       =>  no
          (if (> 3 2)
              (- 3 2)
              (+ 3 2))                =>  1

代入
--

 -- 必須 構文: set! <変数> <式>

     <式> が評価され，その結果の値が，<変数> が束縛されている場所に格納される。 <変数> は，その set! 式を取り囲むどれかの領域またはトップ・レベルにおいて束縛されていなくてはならない。 set! 式の結果は未規定である。

          (define x 2)
          (+ x 1)                     =>  3
          (set! x 4)                  =>  未規定
          (+ x 1)                     =>  5

派生式型
====

参照用に，Formal derived expression typesは，この節で記述されるコンストラクトをさきの節で記述された原始コンストラクトへ変換する書換え規則を与えている。

条件式
---

 -- 必須 構文: cond <節 1> <節 2> ...

     構文：  各 <節> の形式は次のとおりとする。

          (<テスト> <式> ...)

     ここで <テスト> は任意の式である。最後の <節> は次の形式の ``else 節'' であってもよい。

          (else <式 1> <式 2> ...)

     意味：  cond 式は，一連の <節> の <テスト> 式を，その一つが真値 (Booleans参照) へと評価されるまで，順に評価することによって評価される。 <テスト> が真値へと評価されたとき，その <節> の残りの各 <式> が順に評価され，その <節> の最後の <式> の結果が cond 式全体の結果として返される。もし選択された <節> が <テスト> しか含まず，<式> がないときは， <テスト> の値が結果として返される。すべての <テスト> が偽値へと評価されたとき，その条件式の値は未規定である。ただし，もし else 節があるならば，その各 <式> が評価され，その最後の値が返される。

          (cond ((> 3 2) 'greater)
                ((< 3 2) 'less))      =>  greater

          (cond ((> 3 3) 'greater)
                ((< 3 3) 'less)
                (else 'equal))        =>  equal

     一部の実装は代替的な <節> 構文， (<テスト> => <受取先>) をサポートする。ここで <受取先> は１個の式である。もし <テスト> が真値へと評価されたならば，<受取先> が評価される。その値は１引数の手続きでなければならず，この手続きが <テスト> の値を引数として呼び出される。

          (cond ((assv 'b '((a 1) (b 2))) => cadr)
                (else #f))     =>  2

 -- 必須 構文: case <キー> <節 1> <節 2> ...

     構文：  <キー> はどんな式でもよい。各 <節> の形式は次のとおりとする。

          ((<データ 1> ...) <式 1> <式 2> ...)

     ここで各 <データ> はなんらかのオブジェクトの外部表現である。 <データ> はすべて異なっていなければならない。最後の <節> は次の形式の ``else 節'' であってもよい。

          (else <式 1> <式 2> ...)

     意味：  case 式は次のように評価される。 <キー> が評価され，そしてその結果が各 <データ> と比較される。もし <キー> の評価結果が <データ> と (eqv? の意味で) 等価ならば (Equivalence predicates参照)，それに対応する <節> の各式が左から右へと評価され，そしてその <節> の最後の式の結果が case 式の結果として返される。 <キー> の評価結果がどの <データ> とも違うときは，もし else 節があればその各式が評価されてその最後の結果が case 式の結果となるが，なければ case 式の結果は未規定である。

          (case (* 2 3)
            ((2 3 5 7) 'prime)
            ((1 4 6 8 9) 'composite)) =>  composite
          (case (car '(c d))
            ((a) 'a)
            ((b) 'b))                 =>  未規定
          (case (car '(c d))
            ((a e i o u) 'vowel)
            ((w y) 'semivowel)
            (else 'consonant))        =>  consonant

 -- 必須 構文: and <テスト 1> ...

     各 <テスト> 式が左から右へと評価され，最初に偽値 (Booleans参照) へと評価された式の値が返される。残りの式はどれも評価されない。もしすべての式が真値へと評価されたときは，最後の式の値が返される。式が一つもないときは #t が返される。

          (and (= 2 2) (> 2 1))       =>  #t
          (and (= 2 2) (< 2 1))       =>  #f
          (and 1 2 'c '(f g))         =>  (f g)
          (and)                       =>  #t

 -- 必須 構文: or <テスト 1> ...

     各 <テスト> 式が左から右へと評価され，最初に真値 (Booleans参照) へと評価された式の値が返される。残りの式はどれも評価されない。もしすべての式が偽値へと評価されたときは，最後の式の値が返される。式が一つもないときは #f が返される。

          (or (= 2 2) (> 2 1))        =>  #t
          (or (= 2 2) (< 2 1))        =>  #t
          (or #f #f #f)               =>  #f
          (or (memq 'b '(a b c))
              (/ 3 0))                =>  (b c)

束縛コンストラクト
---------

三つの束縛コンストラクト let，let*， letrec は Scheme に Algol 60 のようなブロック構造を与える。三つのコンストラクトは，構文は同一だが，その変数束縛のためにそれらが設ける領域が異なる。 let 式は各初期値をすべて計算してから変数を束縛する。 let* 式は束縛と評価を一つ一つ逐次的に行う。これに対し letrec では，初期値を計算している間すべての束縛が有効であり，したがって相互再帰的な定義が可能である。

 -- 必須 構文: let <束縛部> <本体>

     構文：  <束縛部> の形式は次のとおりとする。

          ((<変数 1> <初期値 1>) ...)

     ここで各 <初期値> は一つの式である。 <本体> は１個以上の式からなる列とする。束縛される変数の並びのなかに一つの <変数> が複数回現れることはエラーである。

     意味：  各 <初期値> が，現在の環境のなかで (ある未規定の順序で) 評価される。その結果を保持する新しい場所へそれぞれの <変数> が束縛される。その拡張された環境のなかで <本体> が評価される。そして <本体> の最後の式の値が返される。 <変数> のどの束縛も <本体> をその領域とする。

          (let ((x 2) (y 3))
            (* x y))                  =>  6

          (let ((x 2) (y 3))
            (let ((x 7)
                  (z (+ x y)))
              (* z x)))               =>  35

     Iterationの名前付き let も見よ。

 -- 構文: let* <束縛部> <本体>

     構文：  <束縛部> の形式は次のとおりとする。

          ((<変数 1> <初期値 1>) ...)

     <本体> は１個以上の式からなる列とする。

     意味：  let* は let とよく似ているが，束縛は逐次的に左から右へと行われる。そして (<変数> <初期値>) により示される一つの束縛は， let* 式のうちで自分よりも右の部分をその領域とする。したがって，２番目の束縛は１番目の束縛が可視であるような環境でなされ，３番目の束縛は１番目と２番目の束縛が可視であるような環境でなされる等々。

          (let ((x 2) (y 3))
            (let* ((x 7)
                   (z (+ x y)))
              (* z x)))               =>  70

 -- 必須 構文: letrec <束縛部> <本体>

     構文：  <束縛部> の形式は次のとおりとする。

          ((<変数 1> <初期値 1>) ...)

     <本体> は１個以上の式からなる列とする。束縛される変数の並びのなかに一つの <変数> が複数回現れることはエラーである。

     意味：  未定義値を保持する新しい場所へ各 <変数> が束縛される。そしてその結果として得られた環境のなかで各 <初期値> が (ある未規定の順序で) 評価される。各 <変数> に，対応する <初期値> の結果が代入される。そしてその結果として得られた環境のなかで <本体> が評価され， <本体> の最後の式の値が返される。 <変数> のどの束縛も letrec 式全体をその領域とするから，相互再帰的な手続きの定義が可能である。

          (letrec ((even?
                    (lambda (n)
                      (if (zero? n)
                          #t
                          (odd? (- n 1)))))
                   (odd?
                    (lambda (n)
                      (if (zero? n)
                          #f
                          (even? (- n 1))))))
            (even? 88))
                                      =>  #t

     letrec には重大な一つの制限がある。つまり，各 <初期値> は，どの <変数> の値も参照または代入することなく評価可能でなくてはならない。この制限への違反はエラーである。この制限が必要なのは，Scheme が引数を名前でなく値で渡すからである。最も一般的な letrec の用途では <初期値> はすべてλ式だから，この制限は自動的に満たされる。

逐次化
---

 -- 必須 構文: begin <式 1> <式 2> ...

     各 <式> が逐次的に左から右へと評価され，最後の <式> の値が返される。この式型は入出力などの副作用を順序どおりに配列するために使われる。

          (define x 0)

          (begin (set! x 5)
                 (+ x 1))             =>  6

          (begin (display "4 plus 1 equals ")
                 (display (+ 4 1)))   =>  未規定
                  および 4 plus 1 equals 5 を印字

     注：  [SICP] は begin のかわりにキーワード sequence を使用している。

繰返し
---

 -- 構文: do <束縛部> <節> <本体>

     構文：  <束縛部> の形式は次のとおりとする。

          ((<変数 1> <初期値 1> <ステップ 1>) ...)

     <節> の形式は次のとおりとする。

          (<テスト> <式> ...)

     <本体> は１個以上の式からなる列とする。

     do は繰返しコンストラクトである。これは束縛すべき変数の集合，それらの開始時点での初期化方法，そしてそれらの各繰返しごとの更新方法を指定する。終了条件が満たされたとき，そのループは指定された結果の値をもって終わる。

     do 式は次のように評価される。各 <初期値> 式が (ある未規定の順序で) 評価される。各 <変数> が新しい場所に束縛され，各 <初期値> 式の結果が各 <変数> の束縛のなかに格納される。そして繰返しが始まる。

     それぞれの繰返しは <テスト> を評価することで始まる。その結果が偽 (Booleans参照) ならば， <本体> の各式がループ本体として順に評価され，各 <ステップ> 式がある未規定の順序で評価され，各 <変数> が新しい場所に束縛され，各 <ステップ> 式の結果が各 <変数> の束縛のなかに格納され，そして次の繰返しが始まる。

     もし <テスト> が真値へと評価されたならば，各 <式> が左から右へと評価され，最後の <式> の値が do 式の値として返される。もし <式> が１個もないならば，do 式の値は未規定である。

     <変数> の束縛の領域は，全 <初期値> を除く do 式全体である。 do 変数の並びのなかに一つの <変数> が複数回現れることはエラーである。

     <ステップ> を省略してもよい。このとき，その効果は (<変数> <初期値>) のかわりに (<変数> <初期値> <変数>) と書いた場合と同じである。

          (do ((vec (make-vector 5))
               (i 0 (+ i 1)))
              ((= i 5) vec)
            (vector-set! vec i i))    =>  #(0 1 2 3 4)

          (let ((x '(1 3 5 7 9)))
            (do ((x x (cdr x))
                 (sum 0 (+ sum (car x))))
                ((null? x) sum)))     =>  25

 -- 構文: let <変数> <束縛部> <本体>

     Scheme のいくつかの実装は ``名前付き let'' という let の構文の一変種を許す。これは do よりも一般的なループ用コンストラクトを与え，再帰を表現するために使うことさえできる。

     名前付き let は，<本体> のなかで <変数> を，束縛される変数を仮引数とし <本体> を本体とするような手続きへと束縛する，という点を除けば，通常の let と同じ構文と意味をもつ。したがって，<変数> を名前とする手続きを呼び出すことによって， <本体> の実行を繰り返すことができる。

          (let loop ((numbers '(3 -2 1 6 -5))
                     (nonneg '())
                     (neg '()))
            (cond ((null? numbers) (list nonneg neg))
                  ((>= (car numbers) 0)
                   (loop (cdr numbers)
                         (cons (car numbers) nonneg)
                         neg))
                  ((< (car numbers) 0)
                   (loop (cdr numbers)
                         nonneg
                         (cons (car numbers) neg)))))
                                      =>  ((6 1 3) (-5 -2))

遅延評価
----

 -- 構文: delay <式>

     delay コンストラクトは，遅延評価 つまり call by need を実装するため，手続き force とともに使われる。 (delay <式>) は約束 (promise) と呼ばれるオブジェクトを返す。このオブジェクトは，<式> を評価して結果の値をかなえることを，未来のある時点で (force 手続きによって) 求められるかもしれない。

     delay のより完全な記述については force (Control features) の記述を見よ。

準引用
---

 -- 必須 構文: quasiquote <テンプレート>
 -- 必須 構文: ` <テンプレート>

     ``バッククォート''式 つまり ``準引用''式は，リストまたはベクタのあるべき構造が前もってほとんど分かっているが完全にではない場合に，そのリストまたはベクタ構造を構築するのに有用である。もしコンマが <テンプレート> のなかに全くなければ， `<テンプレート> の評価結果は '<テンプレート> の評価結果と等価である。しかし，もしコンマが <テンプレート> のなかにあれば，コンマに続く式が評価され (``unquote'' され)，その結果がコンマと式のかわりにその構造のなかに書き込まれる。もしコンマの直後が @ ならば，それに続く式の評価結果はリストでなければならない。この場合，そのリストの両端の丸カッコが``はぎとられ''て，リストの各要素が コンマ @ 式 の列の位置に書き込まれる。

          `(list ,(+ 1 2) 4)          =>  (list 3 4)
          (let ((name 'a)) `(list ,name ',name))
                                      =>  (list a (quote a))
          `(a ,(+ 1 2) ,@(map abs '(4 -5 6)) b)
                                      =>  (a 3 4 5 6 b)
          `((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons)))
                                      =>  ((foo 7) . cons)
          `#(10 5 ,(sqrt 4) ,@(map sqrt '(16 9)) 8)
                                      =>  #(10 5 2 4 3 8)

     準引用形式は入れ子にしてもよい。置換は最外のバッククォートと同じ入れ子レベルにある unquote の要素に対してだけ行われる。入れ子レベルは，準引用に入って行くたびに１だけ増え， unquote の要素に入って行くたびに 1 だけ減る。

          `(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)
                                    =>  (a `(b ,(+ 1 2) ,(foo 4 d) e) f)
          (let ((name1 'x)
                (name2 'y))
            `(a `(b ,,name1 ,',name2 d) e))
                                      =>  (a `(b ,x ,'y d) e)

     記法 `<テンプレート> と (quasiquote <テンプレート>) はすべての点で同一である。 ,<式> は (unquote <式>) と同一である。 ,@<式> は (unquote-splicing <式>) と同一である。 car 部がこれらのシンボルのどれかであるような２要素リストに対して write が生成する外部構文は実装ごとに異なってもよい。

          (quasiquote (list (unquote (+ 1 2)) 4))
                                      =>  (list 3 4)
          '(quasiquote (list (unquote (+ 1 2)) 4))
                                      =>  `(list ,(+ 1 2) 4)
               i.e., (quasiquote (list (unquote (+ 1 2)) 4))

     もしシンボル quasiquote，unquote，または unquote-splicing のどれかが，上述したような位置以外のところで <テンプレート> のなかに現れた場合は，予測できない振舞がもたらされかねない。

プログラム構造
*******

プログラム
=====

Scheme プログラムは，式と定義の列から成り立つ。式はExpressionsで記述されている。定義は本章のこれ以降の主題である。

プログラムは典型的にはファイルに格納されるか，または実行中の Scheme システムに対し対話的に入力されるが，他のパラダイムも可能である。ユーザ・インタフェースの問題はこの報告書の範囲外である。 (実際，Scheme はたとえ機械上の実装がなくても計算方法を表現する記法として依然有用である)。

プログラムのトップ・レベルに出現する定義は，宣言的に解釈される。それらの定義は束縛をトップ・レベルの環境のなかに造らせる。プログラムのトップ・レベルに出現する式は，命令的に解釈される。それらの式は，プログラムが起動またはロードされたときに順に実行され，そして典型的にはなんらかの種類の初期化を行う。

定義
==

定義は，式が許される文脈の，全部ではなく一部において妥当である。定義は <プログラム> のトップ・レベル，および実装によっては <本体> の先頭でだけ妥当である。

定義の形式は次のうちの一つとする。

  * (define <変数> <式>)

     この構文は必須である。

  * (define (<変数> <仮引数部>) <本体>)

     この構文は必須ではない。 <仮引数部> は，０個以上の変数の列であるか，または１個以上の列にスペースで区切られたピリオドともう１個の変数が続いたものとする (λ式と同様である)。この形式は次と等価である。

          (define <変数>
            (lambda (<仮引数部>) <本体>))

  * (define (<変数> . <仮引数>) <本体>)

     この構文は必須ではない。 <仮引数> は単一の変数とする。この形式は次と等価である。

          (define <変数>
            (lambda <仮引数> <本体>))

  * (begin <定義 1> ...)

     この構文は必須である。この形式は，begin の本体をつくる各定義のセットと等価である。

トップ・レベル定義
---------

プログラムのトップ・レベルにおいて，定義

     (define <変数> <式>)

は，もし <変数> が束縛されているならば，必須的に代入式

     (set! <変数> <式>)

と同じ効果をもつ。しかし，もし <変数> が未束縛ならば，定義は代入を実行する前にまず <変数> を新しい場所に束縛する。一方，未束縛の変数に対して set! を実行するとエラーになるだろう。

     (define add3
       (lambda (x) (+ x 3)))
     (add3 3)                    =>  6
     (define first car)
     (first '(1 2))              =>  1

すべての Scheme 実装はトップ・レベル定義をサポートしなければならない。

Scheme のいくつかの実装は，初期環境として，可能なあらゆる変数が束縛されそしてその束縛先の場所の大多数が未定義値を入れているような環境を使う。このような実装ではトップ・レベル定義は代入と全く等価である。

内部定義
----

Scheme のいくつかの実装は，定義が <本体> (つまり lambda， let，let*，letrec または define の式の本体) の先頭に出現することを許す。このような定義を，上述のトップ・レベル定義に対抗して内部定義 (internal definition) という。内部定義で定義される変数は <本体> にローカルである。つまり，<変数> は代入されるのではなく束縛されるのであり，その束縛の領域は <本体> 全体である。たとえば，

     (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 式がそうであるように， <本体> の中の各内部定義のそれぞれの <式> は，定義されるどの <変数> の値の代入も参照もすることなく評価可能でなければならない。

標準手続き
*****

この章は Scheme の組込み手続きを記述する。初期の (または ``トップ・レベル'' の) Scheme 環境は，有用な値を収めている場所に束縛された数多くの変数を伴って始まる。その値の大多数はデータを操作するプリミティブ手続きである。たとえば，変数 abs は数の絶対値を計算する１引数の手続き (を初期値として収めている場所) に束縛され，変数 + は和を計算する手続きに束縛される。

ブーリアン
=====

真および偽をあらわす標準的なブーリアン・オブジェクトは #t および #f と書かれる。しかし，本当に重要なのは，Scheme の条件式 (if，cond， and，or，do) が真または偽として扱うオブジェクトである。 ``真値'' (または単に ``真'') という表現は，どんなオブジェクトであれ条件式が真として扱うオブジェクトを意味し， ``偽値'' (または ``偽'') という表現は，どんなオブジェクトであれ条件式が偽として扱うオブジェクトを意味する。

すべての標準的な Scheme 値のなかで，ただ #f だけが条件式で偽とみなされる。 #f を除くすべての標準的な Scheme 値は， #t，ペア，空リスト，シンボル，数，文字列，ベクタ，および手続きを含め，真とみなされる。

注：  実装によっては，上記に反して，空リストを偽とみなす。しかしながら，この報告書にあるいくつかの例は， [IEEESCHEME] と同様，空リストを偽とみなすことを仮定している。

注：  他の Lisp 方言に慣れているプログラマは， Scheme が #f および空リストをシンボル nil と区別していることに注意するべきである。

ブーリアン定数はそれ自身へと評価されるから，プログラムのなかでそれらをクォートする必要はない。

     #t                          =>  #t
     #f                          =>  #f
     '#f                         =>  #f

 -- 必須 手続き: not obj

     not は OBJ が偽ならば #t を返し，そうでなければ #f を返す。

          (not #t)                    =>  #f
          (not 3)                     =>  #f
          (not (list 3))              =>  #f
          (not #f)                    =>  #t
          (not '())                   =>  #f
          (not (list))                =>  #f
          (not 'nil)                  =>  #f

 -- 必須 手続き: boolean? obj

     boolean? は OBJ が #t または #f のどちらかならば #t を返し，そうでなければ #f を返す。

          (boolean? #f)               =>  #t
          (boolean? 0)                =>  #f
          (boolean? '())              =>  #f

等価性述語
=====

述語とは，いつでもブーリアン値 (#t または #f) を返す手続きである。等価性述語 (equivalence predicate) とは，計算において数学的な同値関係にあたるものである (これには対称律と反射律と推移律が成り立つ)。この節で記述する等価性述語のうち， eq? が最も繊細である，つまり最も微妙な差を区別する。そして equal? が最も粗雑である。 eqv? は eq? よりもわずかに粗く区別する。

 -- 必須 手続き: eqv? obj1 obj2

     eqv? 手続きはオブジェクトに対しある有用な同値関係を定義する。簡単にいえば，これは，OBJ1 と OBJ2 が同じオブジェクトと通常みなされるべきならば #t を返す。この関係にはいささか解釈の余地があるが，以下の部分的な eqv? の規定はすべての Scheme の実装に対して成り立つ。

     下記が成り立つとき，eqv? 手続きは #t を返す。

       * OBJ1 と OBJ2 がともに #t かまたはともに #f である。

       * OBJ1 と OBJ2 がともにシンボルであり，そして

               (string=? (symbol->string obj1)
                         (symbol->string obj2))
                                           =>  #t

          注：  Symbolsでほのめかされているように，これは OBJ1 と OBJ2 のどちらもが ``未インターンのシンボル'' でないことを仮定している。この報告書は，実装依存の拡張に関する eqv? の振舞をあえて規定はしない。

       * OBJ1 と OBJ2 がともに数であり，数値的に等しく (=，Numbers参照)，そしてともに正確数かまたはともに不正確数である。

       * OBJ1 と OBJ2 がともに文字であり，そして char=? 手続きによって同じ文字と判定される(Characters)。

       * OBJ1 と OBJ2 がともに空リストである。

       * OBJ1 と OBJ2 が，記憶領域内の同じ場所を指す二つのペア，ベクタ，または文字列である(Storage model)。

       * OBJ1 と OBJ2 が，場所のタグが等しい二つの手続きである(Lambda expressions)。

     下記が成り立つとき，eqv? 手続きは #f を返す。

       * OBJ1 と OBJ2 の型が異なる(Disjointness of types)。

       * OBJ1 と OBJ2 の一方は #t だが他方が #f である。

       * OBJ1 と OBJ2 はともにシンボルだが，しかし

               (string=? (symbol->string OBJ1)
                         (symbol->string OBJ2))
                                           =>  #f

       * OBJ1 と OBJ2 の一方は正確数だが他方が不正確数である。

       * OBJ1 と OBJ2 は，= 手続きが #f を返すような二つの数である。

       * OBJ1 と OBJ2 は，char=? 手続きが #f を返すような二つの文字である。

       * OBJ1 と OBJ2 の一方は空リストだが他方がそうではない。

       * OBJ1 と OBJ2 は，それぞれ別々の場所を指す二つのペア，ベクタ，または文字列である。

       * OBJ1 と OBJ2 は，ある引数に対して異なった振舞をする (異なった値を返す，または異なった副作用をもつ) 二つの手続きである。

          (eqv? 'a 'a)                =>  #t
          (eqv? 'a 'b)                =>  #f
          (eqv? 2 2)                  =>  #t
          (eqv? '() '())              =>  #t
          (eqv? 100000000 100000000)  =>  #t
          (eqv? (cons 1 2) (cons 1 2))=>  #f
          (eqv? (lambda () 1)
                (lambda () 2))        =>  #f
          (eqv? #f 'nil)              =>  #f
          (let ((p (lambda (x) x)))
            (eqv? p p))               =>  #t

     下記の例は，上記の規則が eqv? の振舞を完全には規定していないケースを挙げている。このようなケースについて言えることは，eqv? の返す値はブーリアンでなければならない，ということだけである。

          (eqv? "" "")                =>  未規定
          (eqv? '#() '#())            =>  未規定
          (eqv? (lambda (x) x)
                (lambda (x) x))       =>  未規定
          (eqv? (lambda (x) x)
                (lambda (y) y))       =>  未規定

     次の一組の例は，ローカルな状態をもった手続きでの eqv? の使用を示している。どうみても gen-counter の返す手続きは毎回異なっていると考えられる。なぜなら，その手続きはそれぞれ自分自身の内部カウンタをもつからである。しかしながら，gen-loser の返す手続きは毎回等価である。なぜなら，そのローカルな状態は手続きの値にも副作用にも影響を及ぼさないからである。

          (define gen-counter
            (lambda ()
              (let ((n 0))
                (lambda () (set! n (+ n 1)) n))))
          (let ((g (gen-counter)))
            (eqv? g g))               =>  #t
          (eqv? (gen-counter) (gen-counter))
                                      =>  #f
          (define gen-loser
            (lambda ()
              (let ((n 0))
                (lambda () (set! n (+ n 1)) 27))))
          (let ((g (gen-loser)))
            (eqv? g g))               =>  #t
          (eqv? (gen-loser) (gen-loser))
                                      =>  未規定

          (letrec ((f (lambda () (if (eqv? f g) 'both 'f)))
                   (g (lambda () (if (eqv? f g) 'both 'g)))
            (eqv? f g))
                                      =>  未規定

          (letrec ((f (lambda () (if (eqv? f g) 'f 'both)))
                   (g (lambda () (if (eqv? f g) 'g 'both)))
            (eqv? f g))
                                      =>  #f

     定数オブジェクト (リテラル式が返すオブジェクト) を改変することはエラーだから，実装が適切に定数どうしの構造を共有化することは，要求されてはいないが許されている。したがって，定数についての eqv? の値は実装依存であることがある。

          (eqv? '(a) '(a))            =>  未規定
          (eqv? "a" "a")              =>  未規定
          (eqv? '(b) (cdr '(a b)))    =>  未規定
          (let ((x '(a)))
            (eqv? x x))               =>  #t

     根拠：  上記の eqv? の定義は，手続きとリテラルの扱いに関して実装に自由度を許している。実装は，二つの手続きまたは二つのリテラルが互いに等価であることを見抜いてもよく，また見抜けなくてもよい。二つのオブジェクトを表現するために同一のポインタまたはビット・パターンが使われていることをもって，それらが等価なオブジェクトであることの代わりとするかどうかは，実装が決めることである。

 -- 必須 手続き: eq? obj1 obj2

     eq? は eqv? とよく似ている。ただ，いくつかの場合において，eqv? が検出できる違いよりもさらに微妙な違いを見分けることができるという点だけが異なる。

     eq? と eqv? はシンボル，ブーリアン，空リスト，ペア，および非空な文字列とベクタについては同じ振舞をすることが保証されている。数と文字についての eq? の振舞は実装依存だが，いつでも真か偽を返し，そして真を返すのは eqv? もまた真を返すようなときに限られる。 eq? はまた空ベクタと空文字列について eqv? と違った振舞をしてもよい。

          (eq? 'a 'a)                 =>  #t
          (eq? '(a) '(a))             =>  未規定
          (eq? (list 'a) (list 'a))   =>  #f
          (eq? "a" "a")               =>  未規定
          (eq? "" "")                 =>  未規定
          (eq? '() '())               =>  #t
          (eq? 2 2)                   =>  未規定
          (eq? #\A #\A)               =>  未規定
          (eq? car car)               =>  #t
          (let ((n (+ 2 3)))
            (eq? n n))                =>  未規定
          (let ((x '(a)))
            (eq? x x))                =>  #t
          (let ((x '#()))
            (eq? x x))                =>  #t
          (let ((p (lambda (x) x)))
            (eq? p p))                =>  #t

     根拠：  普通，eq? は eqv? よりもずっと効率的に，たとえばなにか複雑な演算の代わりに単純なポインタ比較として，実装することが可能だろう。なぜなら一つには，必ずしも二つの数の eqv? を定数時間で計算できるとは限らないからである。これに対し，ポインタ比較として実装された eq? はいつでも定数時間で終了するだろう。手続きを使って状態付きオブジェクトを実装するアプリケーションでは， eq? は eqv? と同じ制約に従うから，eq? を eqv? のように使ってもよい。

 -- 必須 手続き: equal? obj1 obj2

     equal? は再帰的にペア，ベクタ，文字列の内容を比較し，数やシンボルなどそれ以外のオブジェクトには eqv? を適用する。大雑把な原則として，同じように印字されるオブジェクトどうしは一般に equal? である。もし引数が循環データ構造ならば，equal? は停止しないかもしれない。

          (equal? 'a 'a)              =>  #t
          (equal? '(a) '(a))          =>  #t
          (equal? '(a (b) c)
                  '(a (b) c))         =>  #t
          (equal? "abc" "abc")        =>  #t
          (equal? 2 2)                =>  #t
          (equal? (make-vector 5 'a)
                  (make-vector 5 'a)) =>  #t
          (equal? (lambda (x) x)
                  (lambda (y) y))     =>  未規定

ペアとリスト
======

ペア (ときには点対，dotted pair とも呼ばれる) は， (歴史的な理由から) car 部および cdr 部と呼ばれる二つのフィールドをもったレコード構造である。ペアは手続き cons によって造られる。 car 部と cdr 部は手続き car と cdr によってアクセスされる。 car 部と cdr 部は手続き set-car! と set-cdr! によって代入される。

ペアは第一義的にはリストを表現するために使われる。リストは再帰的に，空リスト，または cdr がリストであるようなペアと定義できる。より正確には，リストの集合は下記を満たす最小の集合 X と定義される。

  * 空リストは X の要素である。

  * もし LIST が X の要素ならば，cdr 部に LIST を格納しているペアもまたなんであれ X の要素である。

リストの一連のペアの各 car 部にあるオブジェクトは，そのリストの要素である。たとえば，２要素リストとは，car が第１要素で cdr がペアであり，そしてそのペアの car が第２要素で cdr が空リストであるようなペアである。あるリストの長さとはその要素の個数であり，これはペアの個数と同じである。

空リストは，それ独自の型をもった一つの特別なオブジェクトである (空リストはペアではない)。空リストには要素はなく，その長さは零である。

注：  上記の定義は，すべてのリストが有限の長さをもち，空リストを終端とすることを，暗黙のうちに意味している。

Scheme のペアに対する最も一般性のある記法 (外部表現) は ``点対''記法 (C1 . C2) である。ここで C1 は car 部の値であり，C2 は cdr 部の値である。たとえば (4 . 5) は，car が 4 であり cdr が 5 であるペアである。ただし (4 . 5) はペアの外部表現であって，ペアへと評価される式ではないことに注意せよ。

リストに対してはより簡素化された記法を使用できる。リストの各要素をスペースで区切って丸カッコで囲むだけでよい。空リストは () と書かれる。たとえば，

     (a b c d e)

と

     (a . (b . (c . (d . (e . ())))))

は，あるシンボルからなるリストに対する等価な記法である。

空リストで終わらないペアの連鎖は，仮性リスト (improper list) と呼ばれる。仮性リストはリストではないことに注意せよ。リスト記法と点対記法を組み合わせて仮性リストを表現してもよい。

     (a b c . d)

は次と等価である。

     (a . (b . (c . d)))

あるペアがリストかどうかは，その cdr 部に何が格納されているかに依存する。 set-cdr! 手続きを使うと，あるオブジェクトがあるときはリストであり，またあるときはそうでない，ということが可能である。たとえば，

     (define x (list 'a 'b 'c))
     (define y x)
     y                           =>  (a b c)
     (list? y)                   =>  #t
     (set-cdr! x 4)              =>  未規定
     x                           =>  (a . 4)
     (eqv? x y)                  =>  #t
     y                           =>  (a . 4)
     (list? y)                   =>  #f
     (set-cdr! x x)              =>  未規定
     (list? x)                   =>  #f

リテラル式および read 手続きに読まれるオブジェクトの表現において '<データ> と `<データ> と ,<データ> と ,@<データ> の各形式は２要素リストを表す。その最初の要素はそれぞれシンボル quote，quasiquote，unquote， unquote-splicing であり，第２要素は <データ> である。この規約がサポートされているのは，任意の Scheme プログラムをリストとして表現できるようにするためである。つまり，Scheme の文法によれば，あらゆる <式> はまた <データ> でもあるということである (External representations参照)。とりわけ，このことは read 手続きを使って Scheme プログラムをパースすることを可能にする。 External representationsを見よ。

 -- 必須 手続き: pair? obj

     pair? は OBJ がペアならば #t を返し，そうでなければ #f を返す。

          (pair? '(a . b))            =>  #t
          (pair? '(a b c))            =>  #t
          (pair? '())                 =>  #f
          (pair? '#(a b))             =>  #f

 -- 必須 手続き: cons obj1 obj2

     car が OBJ1 であり，cdr が OBJ2 である新しく割り付けられたペアを返す。このペアは，存在しているどのオブジェクトとも (eqv? の意味で) 異なっていることが保証されている。

          (cons 'a '())               =>  (a)
          (cons '(a) '(b c d))        =>  ((a) b c d)
          (cons "a" '(b c))           =>  ("a" b c)
          (cons 'a 3)                 =>  (a . 3)
          (cons '(a b) 'c)            =>  ((a b) . c)

 -- 必須 手続き: car pair

     PAIR の car 部の内容を返す。空リストの car をとることはエラーであることに注意せよ。

          (car '(a b c))              =>  a
          (car '((a) b c d))          =>  (a)
          (car '(1 . 2))              =>  1
          (car '())                   =>  エラー

 -- 必須 手続き: cdr pair

     PAIR の cdr 部の内容を返す。空リストの cdr をとることはエラーであることに注意せよ。

          (cdr '((a) b c d))          =>  (b c d)
          (cdr '(1 . 2))              =>  2
          (cdr '())                   =>  エラー

 -- 必須 手続き: set-car! pair obj

     OBJ を PAIR の car 部に格納する。 set-car! が返す値は未規定である。

          (define (f) (list 'not-a-constant-list))
          (define (g) '(constant-list))
          (set-car! (f) 3)            =>  未規定
          (set-car! (g) 3)            =>  エラー

 -- 必須 手続き: set-cdr! pair obj

     OBJ を PAIR の cdr 部に格納する。 SET-CDR! が返す値は未規定である。

 -- 必須 手続き: caar pair
 -- 必須 手続き: cadr pair
     ...
 -- 必須 手続き: cdddar pair
 -- 必須 手続き: cddddr pair

     これらの手続きは car と cdr の合成である。ここで，たとえば caddr は次のように定義できる。

          (define caddr (lambda (x) (car (cdr (cdr x)))))

     深さ４までの任意の合成が用意されている。これらの手続きは全部で 28 個ある。

 -- 必須 手続き: null? obj

     もし OBJ が空リストならば #t を返し，そうでなければ #f を返す。

 -- 必須 手続き: list? obj

     もし OBJ がリストならば #t を返し，そうでなければ #f を返す。定義により，すべてのリストは有限の長さをもち，空リストを終端とする。

                  (list? '(a b c))    =>  #t
                  (list? '())         =>  #t
                  (list? '(a . b))    =>  #f
                  (let ((x (list 'a)))
                    (set-cdr! x x)
                    (list? x))        =>  #f

 -- 必須 手続き: list obj ...

     その各引数からなる一つの新しく割り付けられたリストを返す。

          (list 'a (+ 3 4) 'c)        =>  (a 7 c)
          (list)                      =>  ()

 -- 必須 手続き: length list

     LIST の長さを返す。

          (length '(a b c))           =>  3
          (length '(a (b) (c d e)))   =>  3
          (length '())                =>  0

 -- 必須 手続き: append list ...

     最初の LIST の各要素に，ほかの各 LIST の各要素を続けたリストを返す。

          (append '(x) '(y))          =>  (x y)
          (append '(a) '(b c d))      =>  (a b c d)
          (append '(a (b)) '((c)))    =>  (a (b) (c))

     結果として得られたリストは，最後の LIST 引数と構造を共有していることを除けば，すべて新しく割り付けられたものである。最後の引数は実際にはどんなオブジェクトでもよい。ただし，もし最後の引数が真正のリストでなければ，仮性リストが結果として得られる。

          (append '(a b) '(c . d))    =>  (a b c . d)
          (append '() 'a)             =>  a

 -- 必須 手続き: reverse list

     逆順に並べた LIST の各要素からなる一つの新しく割り付けられたリストを返す。

          (reverse '(a b c))          =>  (c b a)
          (reverse '(a (b c) d (e (f))))
                                      =>  ((e (f)) d (b c) a)

 -- 手続き: list-tail list k

     LIST の最初の K 個の要素を省くことで得られる部分リストを返す。 list-tail は次のように定義できる。

          (define list-tail
            (lambda (x k)
              (if (zero? k)
                  x
                  (list-tail (cdr x) (- k 1)))))

 -- 必須 手続き: list-ref list k

     LIST の第 K 番目の要素を返す。 (これは (list-tail LIST K) の car と同じである。)

          (list-ref '(a b c d) 2)     =>  c
          (list-ref '(a b c d)
                    (inexact->exact (round 1.8)))
                                      =>  c

 -- 必須 手続き: memq obj list
 -- 必須 手続き: memv obj list
 -- 必須 手続き: member obj list

     これらの手続きは，OBJ を car とする LIST の最初の部分リストを返す。ここで LIST の部分リストとは，LIST の長さより小さい K に対して (list-tail LIST K) が返す非空なリストである。もし OBJ が LIST に出現しないならば，そのときは (空リストではなく) #f が返される。 memq は eq? を使って OBJ を LIST の各要素と比較するが，memv は eqv? を使い， member は equal? を使う。

          (memq 'a '(a b c))          =>  (a b c)
          (memq 'b '(a b c))          =>  (b c)
          (memq 'a '(b c d))          =>  #f
          (memq (list 'a) '(b (a) c)) =>  #f
          (member (list 'a)
                  '(b (a) c))         =>  ((a) c)
          (memq 101 '(100 101 102))   =>  未規定
          (memv 101 '(100 101 102))   =>  (101 102)

 -- 必須 手続き: assq obj alist
 -- 必須 手続き: assv obj alist
 -- 必須 手続き: assoc obj alist

     ALIST (``association list''，連想リスト) は，ペアからなるリストでなければならない。これらの手続きは，OBJ を car 部とする ALIST の最初のペアを見つけて，そのペアを返す。もし ALIST のどのペアも OBJ を car としないならば，そのときは (空リストではなく) #f が返される。 assq は eq? を使って OBJ を LIST の各ペアの car 部と比較するが， assv は eqv? を使い，assoc は equal? を使う。

          (define e '((a 1) (b 2) (c 3)))
          (assq 'a e)                 =>  (a 1)
          (assq 'b e)                 =>  (b 2)
          (assq 'd e)                 =>  #f
          (assq (list 'a) '(((a)) ((b)) ((c))))
                                      =>  #f
          (assoc (list 'a) '(((a)) ((b)) ((c))))
                                      =>  ((a))
          (assq 5 '((2 3) (5 7) (11 13)))
                                      =>  未規定
          (assv 5 '((2 3) (5 7) (11 13)))
                                      =>  (5 7)

     根拠：  通常は述語として使われるにもかかわらず， memq，memv，member，assq，assv， assoc の名前に ? がないのは，それらが単なる #t，#f 以外の有用な値を返すからである。

シンボル
====

シンボルとは，二つのシンボルが (eqv? の意味で) 同一であるのはそれらの名前が同じようにつづられるときかつそのときに限る，という事実にその有用性がかかっているオブジェクトである。これはまさにプログラムのなかで識別子を表現するために必要とされる性質であり，ほとんどの Scheme の実装はシンボルを内部的にその目的のために利用している。シンボルは他の多くの応用にも有用である。たとえば，Pascal で列挙値を使うようにシンボルを使ってもよい。

シンボルを書くための規則は，識別子を書くための規則と正確に同じである。 IdentifiersとLexical structureを見よ。

リテラル式の一部として返されたかまたは read 手続きを使って読まれたシンボルを，引き続き write 手続きを使って書いた場合，それは (eqv? の意味で) 同一のシンボルとして再び読み込まれることが保証されている。ただし，string->symbol 手続きは，名前に特殊文字や非標準ケースの英字を含めることによって，この write/read 不変性が成り立たないかもしれないシンボルを造ることができる。

注： Scheme の実装によっては，すべてのシンボルについて write/read 不変性を保証するために ``slashification'' という機能がある。しかし，歴史的にこの機能の最も重要な用途は文字列データ型の欠如を補うことであった。

実装によってはまた ``未インターンのシンボル'' というものがある。これは slashification のある実装においてさえ write/read 不変性をくつがえし，かつまた，名前のつづりが同じときかつそのときに限り二つのシンボルは同じである，という規則にも例外を生み出す。

 -- 必須 手続き: symbol? obj

     もし OBJ がシンボルならば #t を返し，そうでなければ #f を返す。

          (symbol? 'foo)              =>  #t
          (symbol? (car '(a b)))      =>  #t
          (symbol? "bar")             =>  #f
          (symbol? 'nil)              =>  #t
          (symbol? '())               =>  #f
          (symbol? #f)                =>  #f

 -- 必須 手続き: symbol->string symbol

     SYMBOL の名前を文字列として返す。もしそのシンボルが，リテラル式 (Literal expressions) の値としてまたは read 手続きの呼出しによって返されたあるオブジェクトの一部だったならば，そしてその名前がアルファベット文字を含んでいるならば，ここで返される文字列は実装が好む標準のケースで文字を含むことになる---大文字を好む実装もあるだろうし，小文字を好む実装もあるだろう。もしそのシンボルが string->symbol によって返されたものだったならば，ここで返される文字列のケースは，元々 string->symbol に渡された文字列のケースと同じになる。この手続きが返す文字列に対して string-set! のような変易手続きを適用することはエラーである。

     以下の例は実装の標準ケースが小文字であると仮定している。

          (symbol->string 'flying-fish)
                                      =>  "flying-fish"
          (symbol->string 'Martin)    =>  "martin"
          (symbol->string
             (string->symbol "Malvina"))
                                      =>  "Malvina"

 -- 必須 手続き: string->symbol string

     STRING を名前とするシンボルを返す。この手続きは，特殊文字や非標準ケースの文字を含んだ名前のシンボルを造ることができる。しかし，そのようなシンボルを造ることは普通，悪いアイディアである。なぜなら，Scheme の実装によっては，そのようなシンボルは自分自身として read することができないからである。 symbol->string を見よ。

     以下の例は実装の標準ケースが小文字であると仮定している。

          (eq? 'mISSISSIppi 'mississippi)
                                      =>  #t
          (string->symbol "mISSISSIppi")
                                    => "mISSISSIppi" という名前のシンボル
          (eq? 'bitBlt (string->symbol "bitBlt"))
                                      =>  #f
          (eq? 'JollyWog
               (string->symbol
                 (symbol->string 'JollyWog)))
                                      =>  #t
          (string=? "K. Harper, M.D."
                    (symbol->string
                      (string->symbol "K. Harper, M.D.")))
                                      =>  #t

数
=

数値計算は伝統的に Lisp コミュニティから無視されてきた。 Common Lisp 以前には数値計算を体系づけるための考え抜かれた戦略は皆無だった。そして，MacLisp システム [PITMAN83] を例外として，数値コードを効率良く実行するための努力はほとんどなされなかった。この報告書は Common Lisp 委員会の労作を高く評価し，その勧告の多くを受け入れる。見方によっては，この報告書はそれらの提案を Scheme の目的に沿うように単純化し一般化しているともいえる。

数学的な数と，それをモデル化しようと試みている Scheme の数と，その Scheme の数を実装するために使われる機械表現と，数を書くために使われる記法とを，それぞれ区別することは重要である。この報告書は number，complex，real，rational，integer という型を，数学的な数と Scheme の数の両方に対して用いる。固定小数点数や浮動小数点数のような機械表現は，fixnum や flonum のような名前によって言い表す。

数値型
---

数学的には，数は，各レベルがそれぞれその上のレベルの部分集合になっているような部分型の塔にまとめることができる。つまり，

  * 数     (number)

  * 複素数 (complex)

  * 実数   (real)

  * 有理数 (rational)

  * 整数   (integer)

たとえば 3 は整数である。したがって 3 は有理数でもあり，実数でもあり，複素数でもある。同じことが，3 をモデル化している Scheme の数についても成り立つ。 Scheme の数に対し，これらの型は述語 number?，complex?， real?，rational?，integer? によって定義される。

ある数がもっている型と，その計算機内部での表現方法との間に，単純な関係はない。 Scheme の大多数の実装は 3 に対し少なくとも二つの異なった表現方法を提供するだろうが，それにもかかわらず，これらの異なった表現方法は 3 という同じ整数を表す。

Scheme の数値演算は数を，可能な限りその表現方法から独立した，抽象データとして取り扱う。 Scheme の実装は数に対して fixnum や flonum やあるいはその他の表現方法を使うかもしれないが，このことは単純なプログラムを書くカジュアルなプログラマに見えるべきではない。

しかし，正確に表現される数とそうとは限らない数を区別することは必要である。たとえば，データ構造への添字は正確に知らなければならない。これは記号代数系での多項式の係数についても同様である。他方，計測の結果というものは本質的に不正確である。また無理数は有理数によって近似されることがあるが，そのときは不正確な近似になる。正確数が要求されるところでの不正確数の使用を捕捉するため， Scheme は正確数と不正確数を明示的に区別する。この区別は型の次元に対して直交的である。

正確性
---

Scheme の数は exact (正確) か inexact (不正確) かのどちらかである。数が正確であるのは，それが正確な定数として書かれたものだったか，あるいは正確な数から正確な演算だけを使って導出されたものだった場合である。数が不正確であるのは，それが不正確な定数として書かれたものだったか，不正確な成分を使って導出されたものだったか，あるいは不正確な演算を使って導出されたものだった場合である。このように不正確性は数のもつ伝染性の性質である。

もし二つの実装が，不正確な中間結果を含むことなく，ある計算に対する正確な結果を算出するならば，その二つの最終結果は数学的に等価になるだろう。一般にこのことは不正確数を含んだ計算には成り立たない。なぜなら，浮動小数点演算のような近似的な方法が使われるかもしれないからである。しかし，その結果を現実的な範囲で数学的に理想的な結果に近付けることは，各実装の義務である。

+ のような有理演算は，正確な引数が与えられたときはいつでも正確な結果を算出するべきである。もしその演算が正確な結果を算出できないならば，実装制限の違反を報告してもよいし，黙ってその結果を不正確な値に変換してもよい。 Implementation restrictionsを見よ。

inexact->exact を例外として，この節で記述される演算は一般に，なんであれ不正確な引数が与えられたときは不正確な結果を返さなければならない。ただし，もし引数の不正確性による影響が結果の値には及ばないと証明できるならば，その演算は正確な結果を返してもよい。たとえば，正確な零との乗算は，たとえもう一方の引数が不正確であっても，正確な零の結果を算出してよい。

実装制限
----

Scheme の実装はNumerical typesで与えられた部分型の塔全体を実装することは要求されていないが，実装の目的と Scheme 言語の精神の両方に沿った一貫性のあるサブセットを実装しなければならない。たとえば，すべての数が実数であるような実装は依然かなり有用かもしれない。

また実装は，この節の要求を満たすかぎり，どの型の数に対してであれ，ある限られた値域だけをサポートすることにしてもよい。どの型であれその正確数に対してサポートする値域と，それと同じ型の不正確数に対してサポートする値域は異なっていてもよい。たとえば，flonum を使ってすべての不正確実数を表現するような実装が，正確な整数と有理数に対しては事実上無限の値域をサポートするにもかかわらず，不正確実数については (そしてそれゆえ不正確な整数と有理数についても) 値域を flonum フォーマットのダイナミック・レンジに制限するようなことがあってもよい。なお，このような実装では，この値域の限界に近付くにつれて，表現可能な不正確整数間および有理数間のギャップが非常に大きくなりやすい。

Scheme の実装は，リストとベクタと文字列の添字として使われ得るかまたはリストかベクタか文字列の長さの計算結果となり得る数の値域全体にわたって，正確整数をサポートしなければならない。 length，vector-length，string-length の各手続きは正確整数を返さなくてはならない。正確整数以外のものを添字として使うことはエラーである。さらに，添字の値域内の整数定数は，もしそれが正確整数の構文で表されているならば，たとえどんな実装制限がこの値域の外に対して適用されていようとも，確かに正確整数として read されるものとする。最後に，下記に挙げた手続きは，もし引数がすべて正確整数であって，そして数学的に期待される結果がその実装で正確整数として表現可能ならば，必ず正確整数の結果を返すものとする。

     +            -             *
     quotient     remainder     modulo
     max          min           abs
     numerator    denominator   gcd
     lcm          floor         ceiling
     truncate     round         rationalize
     expt

実装には，事実上無制限のサイズと精度の正確整数と正確有理数をサポートすること，そして正確な引数が与えられたときにはいつでも正確な結果を返すように上記の手続きと / 手続きを実装することが，要求されてはいないが奨励されている。もしこれらの手続の一つが正確な引数が与えられたときに正確な結果をかなえられないならば，実装制限の違反を報告してもよいし，黙ってその結果を不正確数に変換してもよい。このような変換は後々エラーをひき起こすかもしれない。

実装は浮動小数点およびその他の近似的な表現戦略を不正確数に対して使ってよい。

この報告書は，flonum 表現を使う実装が IEEE 32-bit および 64-bit 浮動小数点標準に従うこと，そして他の表現を使う実装はこれらの浮動小数点標準 [IEEE] を使って達成可能な精度と互角かそれ以上であるべきことを，要求はしないが推奨する。

とりわけ，flonum 表現を使う実装は次の規則に従わなければならない。すなわち，flonum 結果は，その演算への不正確引数を表すために使われたどの精度とも，少なくとも同じだけの精度で表現されなくてはならない。 sqrt のような潜在的に不正確な演算には，正確引数へ適用されたとき，可能ならばいつでも正確な答えを算出することが (要求はされていないが) 要望されている (たとえば正確な 4 の平方根 (square root) は正確な 2 になるべきである)。しかし，もし (sqrt などで) 正確数を演算して不正確な結果が算出されるときには，もしその結果を flonum で表現するならば，利用可能な最も高精度の flonum フォーマットを使わなければならない。一方，もしその結果をなにか別の方法で表現するならば，その表現は利用可能な最も高精度の flonum フォーマットと少なくとも同じだけの精度でなければならない。

Scheme は数を書き表すために様々な記法を許しているが，個々の実装はそれらのいくつかをサポートするだけでもよい。たとえば，すべての数が実数であるような実装は，複素数のための直交座標記法と極座標記法をサポートする必要はない。もし実装が，正確数として表現できない正確数値定数に出会ったならば，その実装は実装制限の違反を報告してもよいし，黙ってその定数を不正確数で表現してもよい。

数値定数の構文
-------

数に対する表記の構文はLexical structureで形式的に記述される。

基数接頭辞を使うことにより，数を２進，８進，または16進で書くことができる。基数接頭辞は #b (binary，２進)，#o (octal，８進)， #d (decimal，10進)，および #x (hexadecimal，16進) である。基数接頭辞がない数は，10進で表されていると仮定される。

接頭辞により，数値定数が正確か不正確かを指定できる。接頭辞 #e は正確 (exact) を表し， #i は不正確 (inexact) を表す。基数接頭辞が使われているとき，正確性接頭辞はその前に現れても後ろに現れてもよい。数の表記に正確性接頭辞がないとき，その定数は不正確かもしれないし正確かもしれない。もしそれが小数点，指数部，または数字がわりの ``#'' 文字を含んでいるならば不正確であり，そうでなければ正確である。

様々な精度の不正確数をもつシステムでは，定数の精度を指定することが有用かもしれない。この目的のため，要望される不正確表現の精度を示す指数部マーカを添えて，数値定数を書いてもよい。文字 s，f，d，および l はそれぞれ SHORT，SINGLE，DOUBLE，および LONG の精度の使用を指定する (不正確数の内部表現が４種類に満たないとき，この四つのサイズ指定は，利用可能なサイズ指定の上へと写像される。たとえば，２種類の内部表現をもつ実装は short と single を一点に，そして long と double を一点に写像するかもしれない)。さらにまた，指数部マーカ e はその実装のデフォルト精度を指定する。デフォルト精度は少なくとも DOUBLE と同じだけの精度をもつが，実装はこのデフォルトをユーザがセットできることを望んでもよい。

     3.14159265358979F0
             single に丸めて --- 3.141593
     0.6L0
             long に拡張して --- .600000000000000

数値演算
----

数値ルーチンへの引数の型に関する制約を指定するために使われる命名規約のまとめについて読者はEntry formatを参照されたい。

この節で使われる例は，正確数の記法を使って書かれた数値定数がどれも実際に正確数として表現されることを仮定する。いくつかの例は，不正確数の記法を使って書かれた数値定数のなかには精度を失うことなく表現できるものがある，ということも仮定する。そして不正確定数は，flonum を使って不正確数を表現する実装においてこれにあてはまりそうなものが選択されている。

 -- 必須 手続き: number? obj
 -- 必須 手続き: complex? obj
 -- 必須 手続き: real? obj
 -- 必須 手続き: rational? obj
 -- 必須 手続き: integer? obj

     これら数値の型述語は，数に限らず，どんな種類の引数にも適用できる。これらは，もしそのオブジェクトが，述語の名前が表す型ならば #t を返し，そうでなければ #f を返す。一般に，もしある型述語がある数について真ならば，それより上にある型述語もすべてその数について真である。したがって，もしある型述語がある数について偽ならば，それより下にある型述語もすべてその数について偽である。

     もし Z が不正確複素数ならば，(real? Z) が真であるのは (zero? (imag-part Z)) が真であるときかつそのときだけである。もし X が不正確実数ならば，(integer? X) が真であるのは (= X (round X)) が真であるときかつそのときだけである。

          (complex? 3+4i)             =>  #t
          (complex? 3)                =>  #t
          (real? 3)                   =>  #t
          (real? -2.5+0.0i)           =>  #t
          (real? #e1e10)              =>  #t
          (rational? 6/10)            =>  #t
          (rational? 6/3)             =>  #t
          (integer? 3+0i)             =>  #t
          (integer? 3.0)              =>  #t
          (integer? 8/4)              =>  #t

     注：  どんな誤差も結果に影響を及ぼす可能性があるから，不正確数に対するこれらの型述語の振舞は信頼できない。

     注：  多くの実装では rational? 手続きは real? と同じになり，complex? 手続きは number? と同じになる。しかし普通でない実装では，いくつかの無理数を正確に表現できたり，ある種の非複素数をサポートするように数の体系を拡張しているかもしれない。

 -- 必須 手続き: exact? z
 -- 必須 手続き: inexact? z

     これらの数値述語は，数量の正確性のテストを与える。どの Scheme 数についても，この二つの述語のうちの正確に一つは真である。

 -- 必須 手続き: = z1 z2 z3 ...
 -- 必須 手続き: < x1 x2 x3 ...
 -- 必須 手続き: > x1 x2 x3 ...
 -- 必須 手続き: <= x1 x2 x3 ...
 -- 必須 手続き: >= x1 x2 x3 ...

     これらの手続きが #t を返すのは (それぞれ) その引数が等しいか，狭義の単調増加をしているか，狭義の単調減少をしているか，広義の単調増加をしているか，または広義の単調減少をしている場合である。

     これらの述語は推移的であることが要求されている。

     注：  Lisp ライクな言語でのこれらの述語の伝統的な実装は推移的ではない。

     注：  これらの述語を使って不正確数を比較することはエラーではないが，その結果は信頼できないかもしれない。小さな誤差が結果に影響を及ぼすかもしれないからである。このことは特に = と zero? について成り立つ。疑わしいときは数値解析学者に相談せよ。

 -- 必須 手続き: zero? z
 -- 必須 手続き: positive? x
 -- 必須 手続き: negative? x
 -- 必須 手続き: odd? n
 -- 必須 手続き: even? n

     これらの数値述語は，特定の性質について数をテストし， #t または #f を返す。上記の注を見よ。

 -- 必須 手続き: max x1 x2 ...
 -- 必須 手続き: min x1 x2 ...

     これらの手続きは，引数の最大値 (maximum) または最小値 (minimum) を返す。

          (max 3 4)                   =>  4    ; 正確
          (max 3.9 4)                 =>  4.0  ; 不正確

     注：  もし引数のどれかが不正確ならば，結果もまた不正確数になる (ただし，その誤差が結果に影響を及ぼすほど十分に大きくないことを手続きが証明できるならばその限りではないが，それが可能なのは普通でない実装だけである)。もし min または max が正確数と不正確数を混合した比較に使われ，そしてその結果の数値が，精度を失っていない不正確数として表現できないならば，その手続きは実装制限の違反を報告してもよい。

 -- 必須 手続き: + z1 ...
 -- 必須 手続き: * z1 ...

     これらの手続きは，引数の和または積を返す。

          (+ 3 4)                     =>  7
          (+ 3)                       =>  3
          (+)                         =>  0
          (* 4)                       =>  4
          (*)                         =>  1

 -- 必須 手続き: - z1 z2
 -- 必須 手続き: - z
 -- 手続き: - z1 z2 ...
 -- 必須 手続き: / z1 z2
 -- 必須 手続き: / z
 -- 手続き: / z1 z2 ...

     引数が２個以上のとき，これらの手続きは，左結合での引数の差または商を返す。しかし，１引数のときは，その引数の加法または乗法での逆元を返す。

          (- 3 4)                     =>  -1
          (- 3 4 5)                   =>  -6
          (- 3)                       =>  -3
          (/ 3 4 5)                   =>  3/20
          (/ 3)                       =>  1/3

 -- 必須 手続き: abs x

     abs は引数の絶対値を返す。

          (abs -7)                    =>  7

 -- 必須 手続き: quotient n1 n2
 -- 必須 手続き: remainder n1 n2
 -- 必須 手続き: modulo n1 n2

     これらの手続きは数論的な (整数の) 割り算を実装する。正の整数 N1 と N2 に対して，もし N3 と N4 が

     (= n1 (+ (* n2 n3) n4))，

     (<= 0 n4)，および

     (< n4 n2)

     を満たす整数ならば，次が成り立つ。

          (quotient N1 N2)            =>  N3
          (remainder N1 N2)           =>  N4
          (modulo N1 N2)              =>  N4

     整数 N1 と N2 ただし N2 ≠ 0 に対して，もし計算に含まれるすべての数が正確数ならば，次が成り立つ。

          (= N1 (+ (* N2 (quotient N1 N2))
                         (remainder N1 N2)))
                                      =>  #t

     quotient の返す値はつねにその引数の積の符号をもつ。 remainder と modulo は負の引数に対して異なる---remainder は零であるかまたは割られる数の符号をもつが， modulo はつねに割る数の符号をもつ。

          (modulo 13 4)               =>  1
          (remainder 13 4)            =>  1

          (modulo -13 4)              =>  3
          (remainder -13 4)           =>  -1

          (modulo 13 -4)              =>  -3
          (remainder 13 -4)           =>  1

          (modulo -13 -4)             =>  -1
          (remainder -13 -4)          =>  -1

          (remainder -13 -4.0)        =>  -1.0  ; 不正確

 -- 必須 手続き: gcd n1 ...
 -- 必須 手続き: lcm n1 ...

     これらの手続きは，引数の最大公約数 (greatest common divisor) または最小公倍数 (least common multiple) を返す。結果はつねに非負である。

          (gcd 32 -36)                =>  4
          (gcd)                       =>  0
          (lcm 32 -36)                =>  288
          (lcm 32.0 -36)              =>  288.0  ; 不正確
          (lcm)                       =>  1

 -- 手続き: numerator q
 -- 手続き: denominator q

     これらの手続きは，引数の分子 (numerator) または分母 (denominator) を返す。結果は，引数が既約の分数として表現されているかのように計算される。分母はつねに正である。0 の分母は 1 であると定義されている。

          (numerator (/ 6 4))         =>  3
          (denominator (/ 6 4))       =>  2
          (denominator
            (exact->inexact (/ 6 4))) =>  2.0

 -- 必須 手続き: floor x
 -- 必須 手続き: ceiling x
 -- 必須 手続き: truncate x
 -- 必須 手続き: round x

     これらの手続きは整数を返す。 floor は X 以下の最大の整数を返す。 ceiling は X 以上の最小の整数を返す。 truncate は絶対値が |X| 以下の X に最も近い整数を返す。 round は X に最も近い整数を返すが，ただし X が二つの整数の中間ならば偶数へと丸める。

     根拠：  round が偶数へと丸めるのは，IEEE 浮動小数点標準で規定されているデフォルト丸めモードに沿うためである。

     根拠：  もしこれらの手続きへの引数が不正確ならば，結果もまた不正確になる。もし正確な値が必要ならば，結果を inexact->exact 手続きへ渡せばよい。

          (floor -4.3)                =>  -5.0
          (ceiling -4.3)              =>  -4.0
          (truncate -4.3)             =>  -4.0
          (round -4.3)                =>  -4.0

          (floor 3.5)                 =>  3.0
          (ceiling 3.5)               =>  4.0
          (truncate 3.5)              =>  3.0
          (round 3.5)                 =>  4.0  ; 不正確

          (round 7/2)                 =>  4    ; 正確
          (round 7)                   =>  7

 -- 手続き: rationalize x y

     rationalize は，X に Y 以内の誤差で等しい最も単純な (simplest) 有理数を返す。ある有理数 R1 が他の有理数 R2 に比べより単純であるのは，次のときである。

     (= r1 (/ p1 q1)) かつ

     (= r2 (/ p2 q2)) (ただし既約分数とする) かつ

     (<= (abs p1) (abs p2)) かつ

     (<= (abs q1) (abs q2)).

     たとえば (3/5) は (4/7) よりも単純である。すべての有理数がこの順序で比較可能というわけではないが ((2/7) と (3/5) を考えてみよ)，いかなる区間にも，その区間内の他のどんな有理数よりも単純であるような１個の有理数が存在する ((2/7) と (3/5) の間には，より単純な (2/5) がある)。 0 (0/1) はすべての有理数のなかで最も単純であることに注意せよ。

          (rationalize
            (inexact->exact .3) 1/10)  =>  1/3    ; 正確
          (rationalize .3 1/10)        =>  #i1/3  ; 不正確

 -- 手続き: exp z
 -- 手続き: log z
 -- 手続き: sin z
 -- 手続き: cos z
 -- 手続き: tan z
 -- 手続き: asin z
 -- 手続き: acos z
 -- 手続き: atan z
 -- 手続き: atan y x

     一般的な実数をサポートする実装はどれもこれらの手続きをもつ。これらは普通の超越関数を計算する。 log は Z の自然対数を計算する (常用対数ではない)。 asin，acos，および atan はそれぞれ arcsine ，arccosine ，および arctangent を計算する。２引数の atan は (angle (make-rectangular X Y)) を計算する (下記を見よ) が，これはたとえ一般的な複素数をサポートしない実装であってもそうである。

     一般に，数学的な関数としての log，arcsine，arcsine，arccosine，および arctangent は多価関数として定義されている。実数 X≠0 に対して (log x) の値は，虚部が区間 (-pi, pi] 内にあるように定義される。 (log 0) は未定義とする。 Z が複素数のとき，(log z) の値は次の公式によって定義される。

          (define (log z) (+ (log (magnitude z)) (* +i (angle z))))

     このように (log) が定義されているとき，arcsin， arccos，および arctan の値は次の公式による。

          (define (asin z) (* -i (log (+ (* +i z) (sqrt (- 1 (* z z)))))))
          (define (acos z) (- (/ pi 2) (asin z)))
          (define (atan z) (/ (log (/ (+ 1 (* +i z)) (- 1 (* +i z))))
                              (* +i 2)))

     上記の規定は [CLTL] に従ったものであり，そしてそれはまた [PENFIELD81] からの引用である。これらの関数の枝のカット，境界条件，および実装方法に関するより詳細な議論については，これらの原典を参照せよ。可能な場合，これらの手続きは実数の引数から実数の結果を算出する。

 -- 手続き: sqrt z

     Z の平方根の主値を返す。結果は正の実部をもつか，あるいは零の実部と非負の虚部をもつ。

 -- 手続き: expt z1 z2

     Z1 の Z2 乗を返す。つまり，

          (define (expt z1 z2) (exp z2 (log z1)))

     (expt 0 0) は 1 に等しいと定義されている。

 -- 手続き: make-rectangular x1 x2
 -- 手続き: make-polar x3 x4
 -- 手続き: real-part z
 -- 手続き: imag-part z
 -- 手続き: magnitude z
 -- 手続き: angle z

     一般的な複素数をサポートする実装はどれもこれらの手続きをもつ。実数 X1，X2，X3，X4 と，複素数 Z が次式を満たすと仮定する。

     (= z (+ x1 (* +i x2) (* x3 (exp (* +i x4)))))

     このとき，make-rectangular と make-polar は Z を返す。 real-part (実部)は X1 を返す。 imag-part (虚部)は X2 を返す。 magnitude (絶対値)は X3 を返す。 angle (偏角)は X4 を返す。 angle の場合，その値は上記の規則からは一意に決まらないが，返される値は区間 (-pi, pi] 内にあるものになる。

     根拠：  実数引数については magnitude は abs と同じである。しかし， abs がすべての実装になければならないのに対して， magnitude は一般的な複素数をサポートする実装にだけあればよい。

 -- 手続き: exact->inexact z
 -- 手続き: inexact->exact z

     exact->inexact は Z の不正確表現を返す。返される値は，引数に数値的に最も近い不正確数である。もし正確数の引数に対して，ほどよい近さの等価な不正確数がないときは，実装制限の違反を報告してもよい。

     inexact->exact は Z の正確表現を返す。返される値は，引数に数値的に最も近い正確数である。もし不正確数の引数に対して，ほどよい近さの等価な正確数がないときは，実装制限の違反を報告してもよい。

     これらの手続きは，ある実装依存の値域にわたって，正確整数と不正確整数の間に自然な一対一の対応を実装する。 Implementation restrictionsを見よ。

数値の入出力
------

 -- 必須 手続き: number->string number
 -- 必須 手続き: number->string number radix

     RADIX は 2，8，10 または 16 のどれかの正確整数でなければならない。省略されたとき，RADIX は 10 をデフォルト値とする。手続き number->string は，数 (NUMBER) と基数 (RADIX) を引数にとり，そして，次式が真であるような，その数のその基数での外部表現を，文字列として返す。

          (let ((number NUMBER)
                (radix RADIX))
            (eqv? number
                  (string->number (number->string number
                                                  radix)
                                  radix)))

     もしこの式を真にするような結果が不可能ならば，エラーである。

     もし NUMBER が不正確であり，基数が 10 であって，小数点を含むような結果によって上記の式を満たすことができるならば，そのとき結果は小数点を含み，上記の式を真にするのに必要な (指数部と末尾の 0 を勘定に入れないで) 最小個数の数字を使って表現される [HOWTOPRINT] [HOWTOREAD]。そうでなければ，結果の書式は未規定である。

     number->string の返す結果は，決して明示的な基数接頭辞をもたない。

     注：  エラーの場合があり得るのは，NUMBER が複素数でないときか，または非有理数の実部または虚部をもつ複素数であるときに限られる。

     注：  もし NUMBER が flonum を使って表現された不正確数で，基数が 10 ならば，上記の式は通常，小数点を含んだ結果によって満たされる。未規定の場合があるのは，無限大，NaN，および非 flonum 表現を考慮してのことである。

 -- 必須 手続き: string->number string
 -- 必須 手続き: string->number string radix

     与えられた STRING が表す最大精度の表現の数を返す。 RADIX は 2，8，10 または 16 のどれかの正確整数でなければならない。 RADIX を与えると，それがデフォルトの基数になる。デフォルトの基数よりも STRING 内の明示的な基数接頭辞 (e.g. "#o177") の方が優先される。 RADIX を与えないとき，デフォルトの基数は 10 になる。もし STRING が数を表す構文的に妥当な記法ではないならば， string->number は #f を返す。

          (string->number "100")      =>  100
          (string->number "100" 16)   =>  256
          (string->number "1e2")      =>  100.0
          (string->number "15##")     =>  1500.0

     注：  string->number は必須手続きではあるが，実装はその定義域を次のように制限してもよい。 STRING に明示的な基数接頭辞があるときはいつでも， string->number は #f を返すことが許される。もし実装がサポートする数が実数だけならば， STRING が複素数の極座標記法または直交座標記法を使っているときはいつでも， string->number は #f を返すことが許される。もし数が整数だけならば，分数記法が使われたときはいつでも， string->number は #f を返してよい。もし数が正確数だけならば，指数部マーカまたは明示的な正確性接頭辞が使われたときはいつでも，あるいは数字がわりに # が現れたときには， string->number は #f を返してよい。もし不正確数が整数だけならば，小数点が使われたときはいつでも， string->number は #f を返してよい。

文字
==

文字は，英字や数字のような印字文字を表すオブジェクトである。文字は #\<文字> または #\<文字名> という記法を使って書かれる。たとえば，

#\a
     英小文字

#\A
     英大文字

#\(
     左の丸カッコ

#\
     スペース文字

#\space
     スペースを書くための好ましい方法

#\newline
     改行文字

ケース (英字の大小) は #\<文字> では意味をもつが， #\<文字名> では無意味である。もし #\<文字> の <文字> がアルファベットならば， <文字> に続く文字はスペースや丸カッコのような区切り文字でなければならない。この規則は，たとえば文字の列 ``#\space'' がスペース文字の表現と文字 ``#\s'' の表現にシンボル ``pace'' の表現が続いたものとのどちらともとれる，というあいまいさを解決する。

#\ 記法で書かれた文字は自己評価的である。つまり，プログラムのなかでそれらをクォートする必要はない。

文字について演算する手続きのいくつかは，大文字と小文字の違いを無視する。ケースを無視する手続きは，その名前の中に ``-ci'' (``case insensitive'' を表す) が組み込まれている。

 -- 必須 手続き: char? obj

     もし OBJ が文字ならば #t を返す。そうでなければ #f を返す。

 -- 必須 手続き: char=? char1 char2
 -- 必須 手続き: char<? char1 char2
 -- 必須 手続き: char>? char1 char2
 -- 必須 手続き: char<=? char1 char2
 -- 必須 手続き: char>=? char1 char2

     これらの手続きは文字の集合にある全順序を課す。この順序のもとでは以下のことが保証される。

       * 大文字はその順序どおりである。たとえば (char<? #\A #\B) は #t を返す。

       * 小文字はその順序どおりである。たとえば (char<? #\a #\b) は #t を返す。

       * 数字はその順序どおりである。たとえば (char<? #\0 #\9) は #t を返す。

       * すべての数字はすべての大文字よりも前であるか，または後である。

       * すべての数字はすべての小文字よりも前であるか，または後である。

     実装は，対応する数値述語と同じく，これらの手続きを２引数以上とるように一般化してもよい。

 -- 必須 手続き: char-ci=? char1 char2
 -- 必須 手続き: char-ci<? char1 char2
 -- 必須 手続き: char-ci>? char1 char2
 -- 必須 手続き: char-ci<=? char1 char2
 -- 必須 手続き: char-ci>=? char1 char2

     これらの手続きは char=? 等々に似ているが，大文字と小文字を同じものとして扱う。たとえば (char-ci=? #\A #\a) は #t を返す。実装は，対応する数値述語と同じく，これらの手続きを２引数以上とるように一般化してもよい。

 -- 必須 手続き: char-alphabetic? char
 -- 必須 手続き: char-numeric? char
 -- 必須 手続き: char-whitespace? char
 -- 必須 手続き: char-upper-case? letter
 -- 必須 手続き: char-lower-case? letter

     これらの手続きは，それぞれその引数がアルファベット文字，数値文字，空白文字，大文字，または小文字ならば #t を返す。そうでなければ #f を返す。以下の注釈は，ASCII 文字セットに固有のものであり，単なる指針として意図されている： アルファベット文字は 52 個の大小英字である。数値文字は 10 個の十進数字である。空白文字はスペース，タブ，改行，改ページ，およびキャリッジ・リターンである。

 -- 必須 手続き: char->integer char
 -- 必須 手続き: integer->char n

     文字が与えられたとき，char->integer はその文字の正確整数表現を返す。ある文字の char->integer による像であるような正確整数が与えられたとき， integer->char はその文字を返す。これらの手続きは，char<=? で順序づけられた文字の集合と， <= で順序づけられた整数のある部分集合との間に，一対一の順序の同型写像を実装する。つまり，もし

     (char<=? A B) => #t  かつ  (<= X Y) => #t

     で，X と Y が integer->char の定義域にあるならば，次が成り立つ。

          (<= (char->integer A)
              (char->integer B))       =>  #t

          (char<=? (integer->char X)
                   (integer->char Y))  =>  #t

 -- 必須 手続き: char-upcase char
 -- 必須 手続き: char-downcase char

     これらの手続きは (char-ci=? CHAR CHAR2) を満たすある文字 CHAR2 を返す。さらに，もし CHAR がアルファベットならば， char-upcase の結果は大文字であり， char-downcase の結果は小文字である。

文字列
===

文字列 (string) は，文字の列 (sequence of characters) である。文字列は二重引用符 (") で囲まれた文字の列として書かれる。二重引用符を文字列の中に書くときは，逆スラッシュ (\) でそれをエスケープする必要がある。たとえば，

     "The word \"recursion\" has many meanings."

逆スラッシュを文字列の中に書くときは，もう一つの逆スラッシュでそれをエスケープする必要がある。文字列の中の，二重引用符も逆スラッシュも後に続かないような逆スラッシュについては，Scheme はその効果を規定しない。

文字列は複数の行にまたがって継続してもよい。ただし，そのような文字列の正確な内容は未規定である。

文字列の長さ (length) とは，その文字列が含む文字の個数である。この数は，その文字列が造られるときに固定されるある非負整数である。文字列の妥当な添字 (valid index) とは，その文字列の長さ未満の正確非負整数である。文字列の最初の文字は添字 0 をもち，その次の文字は添字 1 をもつ等々。

``添字 START で始まり，添字 END で終わる STRING の部分文字列'' という表現では，添字 START は含まれ，添字 END は含まれない，と理解される。したがって，もし START と END が同じ添字ならば，空の部分文字列のことになる。もし START が零であり，END が STRING の長さならば，その STRING 全体のことになる。

文字列について演算する手続きのいくつかは，大文字と小文字の違いを無視する。ケースを無視するバージョンは，その名前の中に ``-ci'' (``case insensitive'' を表す) が組み込まれている。

 -- 必須 手続き: string? obj

     もし OBJ が文字列ならば #t を返す。そうでなければ #f を返す。

 -- 必須 手続き: make-string k
 -- 必須 手続き: make-string k char

     make-string は，長さ K の新しく割り付けられた文字列を返す。 CHAR を与えたときは，文字列の全要素が CHAR に初期化される。そうでないとき，文字列の内容は未規定である。

 -- 必須 手続き: string char ...

     各引数から構成された，新しく割り付けられた文字列を返す。

 -- 必須 手続き: string-length string

     与えられた STRING の文字の個数を返す。

 -- 必須 手続き: string-ref string k

     K は STRING の妥当な添字でなければならない。 string-ref は STRING の零から数えて第 K 番目の文字を返す。

 -- 必須 手続き: string-set! string k char

     K は STRING の妥当な添字でなければならず， CHAR は文字でなければならない。 string-set! は，STRING の第 K 要素に CHAR を格納し，未規定の値を返す。

          (define (f) (make-string 3 #\*))
          (define (g) "***")
          (string-set! (f) 0 #\?)     =>  未規定
          (string-set! (g) 0 #\?)     =>  エラー
          (string-set! (symbol->string 'immutable)
                       0
                       #\?)           =>  エラー

 -- 必須 手続き: string=? string1 string2
 -- 必須 手続き: string-ci=? string1 string2

     もし二つの文字列が同じ長さであり，同じ位置に同じ文字をもつならば， #t を返す。そうでなければ #f を返す。 string-ci=? は英大文字と英小文字をあたかも同じ文字であるかのように扱うが，string=? は大文字と小文字を別々の文字として扱う。

 -- 必須 手続き: string<? string1 string2
 -- 必須 手続き: string>? string1 string2
 -- 必須 手続き: string<=? string1 string2
 -- 必須 手続き: string>=? string1 string2
 -- 必須 手続き: string-ci<? string1 string2
 -- 必須 手続き: string-ci>? string1 string2
 -- 必須 手続き: string-ci<=? string1 string2
 -- 必須 手続き: string-ci>=? string1 string2

     これらの手続きは，対応する文字の順序付けを，文字列へと辞書的に拡張したものである。たとえば，string<? は，文字についての順序付け char<? によって帰納された，文字列についての辞書的な順序付けである。もし二つの文字列が，長さが異なるけれども，短い方の文字列の長さまでは同じならば，長い方の文字列よりも短い方の文字列が辞書的に小さいと見なされる。

     実装は，これらと string=? および string-ci=? の手続きを，対応する数値述語と同じく，２引数以上とるように一般化してもよい。

 -- 必須 手続き: substring string start end

     STRING は文字列でなければならず，START と END は以下を満たす正確整数でなければならない。

     (<= 0 start end (string-length string))

     substring は，添字 START (それ自身を含む)で始まり，添字 END (それ自身は含まない)で終わる STRING の部分文字列を内容とする新しく割り付けられた文字列を返す。

 -- 必須 手続き: string-append string ...

     与えられた文字列の連結を内容とする新しく割り付けられた文字列を返す。

 -- 必須 手続き: string->list string
 -- 必須 手続き: list->string chars

     string->list は，与えられた文字列を構成する各文字からなる新しく割り付けられたリストを返す。 list->string は，リスト CHARS の各文字を内容とする新しく割り付けられた文字列を返す。 string->list と list->string は，equal? に関する限りは逆関数である。

 -- 手続き: string-copy string

     与えられた STRING の新しく割り付けられたコピーを返す。

 -- 手続き: string-fill! string char

     与えられた STRING の各要素に CHAR を格納し，未規定の値を返す。

ベクタ
===

ベクタは不均質な構造体 (heterogenous structure) であり，その要素は整数によって添字付けされる。ベクタは典型的には，同じ長さのリストよりも少ない空間しか占めない。また，ランダムに選んだ要素のアクセスに必要な平均時間は，典型的にはリストよりもベクタの方が短い。

ベクタの長さとは，そのベクタが含む要素の個数である。この数は，そのベクタが造られるときに固定されるある非負整数である。ベクタの妥当な添字とは，そのベクタの長さ未満の正確非負整数である。ベクタの最初の要素は零によって添字付けされ，最後の要素はベクタの長さより 1 だけ小さい整数によって添字付けされる。

ベクタは #(OBJ ...) という記法を使って書かれる。たとえば，第 0 要素に数 0 を，第 1 要素にリスト (2 2 2 2) を，第 2 要素に文字列 "Anna" をもつ長さ 3 のベクタは，次のように書くことができる。

     #(0 (2 2 2 2) "Anna")

これはベクタの外部表現であって，ベクタへと評価される式ではないことに注意せよ。リスト定数と同じく，ベクタ定数はクォートしなければならない。

     '#(0 (2 2 2 2) "Anna")
               =>  #(0 (2 2 2 2) "Anna")

 -- 必須 手続き: vector? obj

     もし OBJ がベクタならば #t を返す。そうでなければ #f を返す。

 -- 必須 手続き: make-vector k
 -- 手続き: make-vector k fill

     K 個の要素からなる新しく割り付けられたベクタを返す。第２引数が与えられているとき，各要素は FILL へと初期化される。そうでないとき，各要素の初期内容は未規定である。

 -- 必須 手続き: vector obj ...

     与えられた各引数を各要素がもつ新しく割り付けられたベクタを返す。 list に相当する。

          (vector 'a 'b 'c)           =>  #(a b c)

 -- 必須 手続き: vector-length vector

     VECTOR の要素の個数を返す。

 -- 必須 手続き: vector-ref vector k

     K は VECTOR の妥当な添字でなければならない。 vector-ref は VECTOR の第 K 要素の内容を返す。

          (vector-ref '#(1 1 2 3 5 8 13 21)
                      5)
                    =>  8
          (vector-ref '#(1 1 2 3 5 8 13 21)
                      (inexact->exact
                        (round (* 2 (acos -1)))))
                    =>  13

 -- 必須 手続き: vector-set! vector k obj

     K は VECTOR の妥当な添字でなければならない。 vector-set! は VECTOR の第 K 要素に OBJ を格納する。 vector-set! の返す値は未規定である。

          (let ((vec (vector 0 '(2 2 2 2) "Anna")))
            (vector-set! vec 1 '("Sue" "Sue"))
            vec)
                    =>  #(0 ("Sue" "Sue") "Anna")

          (vector-set! '#(0 1 2) 1 "doe")
                    =>  エラー  ; 定数ベクタ

 -- 必須 手続き: vector->list vector
 -- 必須 手続き: list->vector list

     vector->list は，VECTOR の各要素として含まれている各オブジェクトからなる新しく割り付けられたリストを返す。 list->vector は，リスト LIST の各要素へと初期化された新しく割り付けられたベクタを返す。

          (vector->list '#(dah dah didah))
                    =>  (dah dah didah)
          (list->vector '(dididit dah))
                    =>  #(dididit dah)

 -- 手続き: vector-fill! vector fill

     VECTOR の各要素に FILL を格納する。 vector-fill! の返す値は未規定である。

制御機能
====

この章は，プログラムの実行の流れを特別な方法で制御する様々なプリミティブ手続きを記述する。 procedure? 述語もここで記述される。

 -- 必須 手続き: procedure? obj

     もし OBJ が手続きならば #t を返す。そうでなければ #f を返す。

          (procedure? car)            =>  #t
          (procedure? 'car)           =>  #f
          (procedure? (lambda (x) (* x x)))
                                      =>  #t
          (procedure? '(lambda (x) (* x x)))
                                      =>  #f
          (call-with-current-continuation procedure?)
                                      =>  #t

 -- 必須 手続き: apply proc args
 -- 手続き: apply proc arg1 ... args

     PROC は手続きでなければならず，ARGS はリストでなければならない。第一の (必須) 形式は PROC を，ARGS の各要素を各実引数として呼び出す。第二の形式は，第一の形式の一般化であり， PROC を，リスト (append (list ARG1 ...) ARGS) の各要素を各実引数として呼び出す。

          (apply + (list 3 4))        =>  7

          (define compose
            (lambda (f g)
              (lambda args
                (f (apply g args)))))

          ((compose sqrt *) 12 75)    =>  30

 -- 必須 手続き: map proc list1 list2 ...

     各 LIST はリストでなければならず，PROC は list の個数と同じだけの引数をとる手続きでなければならない。２個以上の LIST が与えられたとき，それらはすべて同じ長さでなければならない。 map は PROC を LIST の各要素へ要素ごとに適用し，各結果が左から右へ順に並んだリストを返す。 PROC が LIST の各要素へ適用される動的な順序は未規定である。

          (map cadr '((a b) (d e) (g h)))
                                      =>  (b e h)

          (map (lambda (n) (expt n n))
               '(1 2 3 4 5))
                                      =>  (1 4 27 256 3125)

          (map + '(1 2 3) '(4 5 6))   =>  (5 7 9)

          (let ((count 0))
            (map (lambda (ignored)
                   (set! count (+ count 1))
                   count)
                 '(a b c)))           =>  未規定

 -- 必須 手続き: for-each proc list1 list2 ...

     for-each の引数は map の引数と同様だが， for-each は PROC をその値ではなく副作用のために呼び出す。 map と異なり，for-each は LIST の各要素に対し最初の要素から最後の要素へという順序で PROC を呼び出すことが保証されており，そして for-each の返す値は未規定である。

          (let ((v (make-vector 5)))
            (for-each (lambda (i)
                        (vector-set! v i (* i i)))
                      '(0 1 2 3 4))
            v)                        =>  #(0 1 4 9 16)

 -- 手続き: force promise

     約束 (PROMISE) の値を強制する (Delayed evaluation参照)。

     約束に対し値がまだ計算されていないならば，値が計算されて返される。約束の値は，それがもし二度目に強制されたとき以前計算された値を返せるように，キャッシュされる (つまり ``memoize'' される)。

          (force (delay (+ 1 2)))     =>  3
          (let ((p (delay (+ 1 2))))
            (list (force p) (force p)))
                                      =>  (3 3)

          (define a-stream
            (letrec ((next
                      (lambda (n)
                        (cons n (delay (next (+ n 1)))))))
              (next 0)))
          (define head car)
          (define tail
            (lambda (stream) (force (cdr stream))))

          (head (tail (tail a-stream)))
                                      =>  2

     force と delay は，関数的なスタイルで書かれたプログラムでの利用を主に意図している。以下の例は良いプログラミング・スタイルを示していると見なされるべきではないが，一つの約束については，それが何度強制されようとも，ただ一つの値だけが計算されるという性質を示している。

          (define count 0)
          (define p
            (delay (begin (set! count (+ count 1))
                          (if (> count x)
                              count
                              (force p)))))
          (define x 5)
          p                           =>  一つの約束
          (force p)                   =>  6
          p                           =>  依然，一つの約束
          (begin (set! x 10)
                 (force p))           =>  6

     以下は delay と force の一つの可能な実装である。約束はここでは無引数の手続きとして実装され， force は単にその引数を呼び出すだけである:

          (define force
            (lambda (object)
              (object)))

     我々は式

          (delay <式>)

     を，次の手続き呼出しと同じ意味をもつと定義する。

          (make-promise (lambda () <式>))

     ここで make-promise は以下のように定義される。

          (define make-promise
            (lambda (proc)
              (let ((result-ready? #f)
                    (result #f))
                (lambda ()
                  (if result-ready?
                      result
                      (let ((x (proc)))
                        (if result-ready?
                            result
                            (begin (set! result-ready? #t)
                                   (set! result x)
                                   result))))))))

     根拠：  上記の最後の例のように，約束は自分自身の値を参照するかもしれない。このような約束を force すると，その約束に対し，最初の force の値が計算され終わる前に，二度目の force がひき起こされるかもしれない。このことが make-promise の定義を複雑にしている。

     delay と force のこの意味論への様々な拡張が，いくつかの実装でサポートされている:

       * 約束ではないオブジェクトに対する force の呼出しは，単にそのオブジェクトを返してもよい。

       * 約束をその force した値から操作的に区別し得る手段が全くないということがあってもよい。つまり，次のような式は実装により #t と #f のどちらにも評価されてもよい。

               (eqv? (delay 1) 1)          =>  未規定
               (pair? (delay (cons 1 2)))  =>  未規定

       * 実装によっては ``暗黙の強制'' を実装するかもしれない。そこでは約束の値は cdr や + のようなプリミティブ手続きによって force される。

               (+ (delay (* 3 7)) 13)      =>  34

 -- 必須 手続き: call-with-current-continuation proc

     PROC は１引数の手続きでなければならない。手続き call-with-current-continuation は，現在の継続 (下記の根拠を見よ) を ``脱出手続き'' (escape procedure) としてパッケージ化し，それを PROC へ引数として渡す。脱出手続きは１引数の Scheme 手続きである。後でもしその脱出手続きへなにか値を渡すと，それはその時点でどんな継続が有効であっても無視して，その脱出手続きが造られたときに有効だった継続へその値を与える。

     PROC へ渡される脱出手続きは，Scheme の他のすべての手続きと同じように無期限の寿命をもつ。脱出手続きを変数やデータ構造の中に格納して，望むだけの回数呼び出してもよい。

     以下の例は call-with-current-continuation の最もありふれた用途だけを示している。もし実際のプログラムがすべてこれらの例のように単純だったら， call-with-current-continuation のような力をもった手続きは必要なかっただろう。

          (call-with-current-continuation
            (lambda (exit)
              (for-each (lambda (x)
                          (if (negative? x)
                              (exit x)))
                        '(54 0 37 -3 245 19))
              #t))                    =>  -3

          (define list-length
            (lambda (obj)
              (call-with-current-continuation
                (lambda (return)
                  (letrec ((r
                            (lambda (obj)
                              (cond ((null? obj) 0)
                                    ((pair? obj)
                                     (+ (r (cdr obj)) 1))
                                    (else (return #f))))))
                    (r obj))))))

          (list-length '(1 2 3 4))    =>  4

          (list-length '(a b . c))    =>  #f

     根拠： call-with-current-continuation のありふれた用途はループや手続き本体からの非局所的な，構造化された脱出だが，実はそれどころか call-with-current-continuation は広範囲の高度な制御構造の実装に極めて有用である。

     Scheme の式が評価されるときにはいつでも，その式の結果を欲している一つの継続 (continuation) が存在する。継続は，その計算に対する (デフォルトの) 未来全体を表現する。たとえば，もし式がトップ・レベルで評価されているならば，その継続は，式の結果を受け取り，それを画面に表示し，次の入力を催促し，それを評価し，等々を永遠に続けるだろう。たいていの場合，継続はユーザのコードが規定する動作を含む。たとえば，結果を受け取り，あるローカル変数に格納されている値をそれに掛け， 7 を足し，その答えをトップ・レベルの継続に与えて印字させる，というような継続がそうである。通常，これらあまねく存在する継続は舞台裏に隠されており，プログラマはそれらについてあまり考えない。しかし，まれにはプログラマが継続を明示的に取り扱う必要があるかもしれない。 call-with-current-continuation は，全く現在の継続のように振舞う手続きを造ることによって，それを Scheme プログラマに可能にする。

     たいていのプログラミング言語は exit や return，果ては goto のような名前の専用の脱出コンストラクトを一つ以上採り入れている。しかし，1965 年 Peter Landin [LANDIN65] は J 演算子という汎用の脱出演算子を発明した。 John Reynolds [REYNOLDS72] はより単純だが同等に強力なコンストラクトを 1972 年に記述した。 Sussman と Steele によって 1975 年版 Scheme 報告書に記述された catch 特殊形式は，Reynolds のコンストラクトと正確に同じであるが，ただしその名前は MacLisp の中のある汎用性の低いコンストラクトに由来している。何人かの Scheme 実装者は，catch コンストラクトの完全な強力さを，特別な構文のコンストラクトによるかわりに，手続きによって用意できることに気付き，名前 call-with-current-continuation が 1982 年に新造された。この名前は説明的だが，このような長い名前のメリットについては意見の相違があり，一部の人々は call/cc という名前をかわりに使っている。

入力と出力
=====

ポート
---

ポート (port) は入出力装置を表す。 Scheme にとって，入力ポートは文字をコマンドへ伝え渡すことができる Scheme オブジェクトであり，出力ポートは文字を受け取ることができる Scheme オブジェクトである。

 -- 必須 手続き: call-with-input-file string proc
 -- 必須 手続き: call-with-output-file string proc

     PROC は１引数の手続きとする。 STRING はファイルを指名する文字列とする。 call-with-input-file ではそのファイルは既存でなければならないが， call-with-output-file ではもしそのファイルが既存ならば効果は未規定である。これらの手続きは PROC を１個の引数とともに呼び出す。そしてその引数は，指名されたファイルを入力または出力のために開くことによって得られたポートである。もしファイルが開けないときはエラーが通知される。手続きが戻って来たときには，ポートが自動的に閉じられ，そしてその手続きのもたらした値が返される。もし手続きが戻らないならば，ポートは自動的には閉じられないが，ただし，そのポートが read または write 演算に二度と使われないと証明できるならばその限りではない。

     根拠：  Scheme の脱出手続きは無期限の寿命をもつから，現在の継続から脱出した後でも，またさかのぼって脱出することが可能である。もしも現在の継続からのどんな脱出時においてもポートを閉じることを実装に許したら，call-with-current-continuation と call-with-input-file や call-with-output-file をともに使用するポータブルなコードを書くことは不可能になっただろう。

 -- 必須 手続き: input-port? obj
 -- 必須 手続き: output-port? obj

     それぞれ，もし OBJ が入力ポートまたは出力ポートならば #t を返す。そうでなければ #f を返す。

 -- 必須 手続き: current-input-port
 -- 必須 手続き: current-output-port

     現在のデフォルトの入力または出力ポートを返す。

 -- 手続き: with-input-from-file string thunk
 -- 手続き: with-output-to-file string thunk

     THUNK は無引数の手続きでなければならない。 STRING はファイルを指名する文字列でなければならない。 with-input-from-file ではそのファイルは既存でなければならないが， with-output-to-file ではもしそのファイルが既存ならば効果は未規定である。ファイルが入力または出力のために開かれ，それに接続された入力または出力ポートが current-input-port または current-output-port の返すデフォルト値にされ，そして THUNK が無引数で呼び出される。 THUNK が戻って来たときには，ポートが閉じられ，そして以前のデフォルト値が回復される。 with-input-from-file と with-output-to-file は， THUNK がもたらした値を返す。もし脱出手続きがこれらの手続きの継続から脱出するために使われた場合，これらの手続きの振舞は実装依存である。

 -- 必須 手続き: open-input-file filename

     既存のファイルを指名する文字列を引数にとり，そのファイルからの文字を伝え渡すことができる入力ポートを返す。もしファイルが開けないならば，エラーが通知される。

 -- 必須 手続き: open-output-file filename

     造られるべき出力ファイルを指名する文字列を引数にとり，その名前の新しいファイルへ文字を書くことができる出力ポートを返す。もしファイルが開けないならば，エラーが通知される。もし与えられた名前のファイルが既存ならば，効果は未規定である。

 -- 必須 手続き: close-input-port port
 -- 必須 手続き: close-output-port port

     PORT に結合しているファイルを閉じて， PORT がもう文字を伝え渡したり受け取ったりできないようにする。

     これらのルーチンは，もしそのファイルが既に閉じられているならば，なんの効果もない。返される値は未規定である。

入力
--

 -- 必須 手続き: read
 -- 必須 手続き: read port

     read は Scheme オブジェクトの外部表現をオブジェクトそれ自身へと変換する。つまり，これは非終端記号 <データ> に対するパーサである (External representationsおよびPairs and lists参照)。 read は，与えられた入力 PORT からパース可能な次のオブジェクトを返し，PORT を，返したオブジェクトの外部表現の終わりを越えた最初の文字を指すように更新する。

     もし入力でオブジェクトの先頭になり得る文字が見つかる前にファイルの終わりに出会ったならば，end of file オブジェクトが返される。ポートは開いたままであり，さらに read しようとしてもまた end of file オブジェクトが返されることになる。もしオブジェクトの外部表現の先頭の後で，まだその外部表現が完了しておらず，したがってまだパース可能でないときに，ファイルの終わりに出会ったならば，エラーが通知される。

     PORT 引数は省略してもよく，その場合， current-input-port によって返される値をデフォルトとする。閉じたポートから read することはエラーである。

 -- 必須 手続き: read-char
 -- 必須 手続き: read-char port

     入力 PORT から入手可能な次の文字を返し， PORT をその直後の文字を指すように更新する。もしもう文字が入手可能でないならば，end of file オブジェクトが返される。 PORT 引数は省略してもよく，その場合， current-input-port によって返される値をデフォルトとする。

 -- 必須 手続き: peek-char
 -- 必須 手続き: peek-char port

     入力 PORT から入手可能な次の文字を返す。ただし，PORT をその直後の文字を指すように更新することはしない。もしもう文字が入手可能でないならば，end of file オブジェクトが返される。 PORT 引数は省略してもよく，その場合， current-input-port によって返される値をデフォルトとする。

     注：  peek-char の呼出しによって返される値は，同じ PORT から read-char の呼出しによって返されたであろう値と同じである。唯一の違いは，その PORT でのまさにその次の read-char または peek-char の呼出しは，以前の peek-char 呼出しによって返された値を返すことになるという点である。とりわけ，対話的なポートでの peek-char の呼出しは， read-char の呼出しが入力待ちでハングするような場合はいつでも，やはりハングするだろう。

 -- 必須 手続き: eof-object? obj

     もし OBJ が end of file オブジェクトならば #t を返す。そうでなければ #f を返す。 end of file オブジェクトの正確な集合は実装によって異なるが，いずれにせよ end of file オブジェクトは決して read を使って読み込めるオブジェクトではない。

 -- 手続き: char-ready?
 -- 手続き: char-ready? port

     もしなにか文字が入力 PORT で用意できているならば #t を返す。そうでなければ #f を返す。もし char-ready? が #t を返したときは，その PORT での次の read-char 操作はハングしないことが保証される。もし PORT がファイルの終わりにあるときは， char-ready? は #t を返す。 PORT 引数は省略してもよく，その場合， current-input-port によって返される値をデフォルトとする。

     根拠：  char-ready? は，プログラムが入力待ちで止まってしまうことなく対話的ポートから文字を受け取れるようにするために存在する。このようなポートに結合した入力エディタは， char-ready? によっていったん存在が表明された文字が，編集されて消されないようにしなければならない。もしも char-ready? がファイルの終わりで #f を返したとしたら，ファイルの終わりにあるポートを，文字が用意できていない対話的ポートと区別することはできなくなっただろう。

出力
--

 -- 必須 手続き: write obj
 -- 必須 手続き: write obj port

     OBJ の表記表現を，与えられた PORT へ書く。その表現に現れる文字列は二重引用符で囲まれ，その文字列内部の逆スラッシュと二重引用符は逆スラッシュでエスケープされる。 write は未規定の値を返す。 PORT 引数は省略してもよく，その場合， current-output-port によって返される値をデフォルトとする。

 -- 必須 手続き: display obj
 -- 必須 手続き: display obj port

     OBJ の表現を，与えられた PORT へ書く。その表現に現れる文字列は二重引用符で囲まれない。また，その文字列内部のどの文字もエスケープされない。文字オブジェクトは，あたかも write ではなく write-char で書かれたかのような表現で現れる。 display は未規定の値を返す。 PORT 引数は省略してもよく，その場合， current-output-port によって返される値をデフォルトとする。

     根拠：  write は機械可読な出力を生むためにあり， display は人間可読な出力を生むためにある。シンボル内に ``slashification'' を許している実装は，おそらく write にはシンボル内の奇妙な文字を slashify させるが， display にはさせないだろう。

 -- 必須 手続き: newline
 -- 必須 手続き: newline port

     行の終わり (end of line) を PORT へ書く。これが正確にはどのようになされるのかは，オペレーティング・システムによって異なる。未規定の値を返す。 PORT 引数は省略してもよく，その場合， current-output-port によって返される値をデフォルトとする。

 -- 必須 手続き: write-char char
 -- 必須 手続き: write-char char port

     (文字の外部表現ではなく) 文字 CHAR そのものを，与えられた PORT へ書き，未規定の値を返す。 PORT 引数は省略してもよく，その場合， current-output-port によって返される値をデフォルトとする。

システム・インタフェース
------------

システム・インタフェースの問題は一般にこの報告書の範囲を越える。しかし，以下の操作にはここで記述するだけの重要性がある。

 -- 必須 手続き: load filename

     FILENAME は，Scheme ソース・コードを内容とする既存のファイルを指名する文字列とする。 load 手続きは，そのファイルから式と定義を読み，逐次的にそれらを評価する。式の結果が印字されるかどうかは未規定である。 load 手続きは， current-input-port および current-output-port によって返される値には影響を与えない。 load は未規定の値を返す。

     根拠：  ポータビリティのため，load はソース・ファイルに対して操作しなくてはならない。その他の種類のファイルに対する操作は実装間で必然的に異なる。

 -- 手続き: transcript-on filename
 -- 手続き: transcript-off

     FILENAME は造られる出力ファイルを指名する文字列でなければならない。 transcript-on の効果は，指名されたファイルを出力用に開くこと，そしてそれ以降のユーザと Scheme システムとの対話の写し (transcript) がそのファイルへ書かれるようにすることである。この写しは transcript-off の呼出しによって終わり，写しのファイルは閉じられる。一度に一つだけの写しが進行中になり得るが，実装はこの制限を緩和してもよい。これらの手続きによって返される値は未規定である。

形式的な構文と意味論
**********

この章は，この報告書のこれまでの章で非形式的に記述してきたことを形式的に記述する。

形式的構文
=====

この節は，拡張 BNF で書かれた Scheme の形式的構文を定める。必須ではない機能も含め，言語全体に対する構文をここで与える。

文法におけるスペースは，読みやすさのためだけにある。ケースは無意味である。したがって，たとえば #x1A と #X1a は等価である。 <empty> は空文字列を表す。

記述を簡潔にするために BNF を次のように拡張する。 <なにか>* は <なにか> の０回以上の出現を意味する。 <なにか>+ は <なにか> の少なくとも１回以上の出現を意味する。

字句構造
----

この節は，個々のトークン (識別子，数，etc.) がどのように文字の列からつくられるかを記述する。後続の節は，式とプログラムがどのようにトークンの列からつくられるかを記述する。

<トークン間のスペース> は，どのトークンの左右どちらの側に出現してもよいが，トークンの内部に出現してはならない。

暗黙の終端を要求するトークン (識別子，数，文字，およびドット) は，どんな <区切り文字> によってでも終端づけできるが，それ以外のものでは必ずしも終端づけできるとは限らない。

     <トークン> ==> <識別子> | <ブーリアン> | <数>
          | <文字> | <文字列>
          | ( | ) | #( | ' | ` | , | ,@ | .
     <区切り文字> ==> <空白> | ( | ) | " | ;
     <空白> ==> <スペースまたは改行>
     <注釈> ==> ; <これ以降行末へ至るまでのすべての文字>
     <atmosphere> ==> <空白> | <注釈>
     <トークン間のスペース> ==> <atmosphere>*

     <識別子> ==> <initial> <subsequent>*
          | <peculiar identifier>
     <initial> ==> <英字> | <special initial>
     <英字> ==> a | b | c | ... | z
     <special initial> ==> ! | $ | % | & | * | / | : | < | =
          | > | ? | ~ | _ | ^
     <subsequent> ==> <initial> | <数字>
          | <special subsequent>
     <数字> ==> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
     <special subsequent> ==> . | + | -
     <peculiar identifier> ==> + | - | ...
     <構文キーワード> ==> <式キーワード>
          | else | => | define
          | unquote | unquote-splicing
     <式キーワード> ==> quote | lambda | if
          | set! | begin | cond | and | or | case
          | let | let* | letrec | do | delay
          | quasiquote

     <ブーリアン> ==> #t | #f
     <文字> ==> #\ <任意の文字>
          | #\ <文字名>
     <文字名> ==> space | newline

     <文字列> ==> " <string element>* "
     <string element> ==> <" と \ を除く任意の文字>
          | \" | \\

     <数> ==> <2進数> | <8進数>
          | <10進数> | <16進数>

以下の <R進数>，<複素数 R>，<実数 R>， <ureal R>，<uinteger R>，<接頭辞 R> に対する規則は R = 2, 8, 10, 16 に対してそれぞれ繰り返されるものとする。 <decimal 2>，<decimal 8>，<decimal 16> に対する規則はないが，これは小数点または指数部をもつ数は必ず十進数であるということを意味する。

     <R進数> ==> <接頭辞 R> <複素数 R>
     <複素数 R> ==> <実数 R> | <実数 R> @ <実数 R>
          | <実数 R> + <ureal R> i | <実数 R> - <ureal R> i
          | <実数 R> + i | <実数 R> - i
          | + <ureal R> i | - <ureal R> i | + i | - i
     <実数 R> ==> <符号> <ureal R>
     <ureal R> ==> <uinteger R>
          | <uinteger R> / <uinteger R>
          | <decimal R>
     <decimal 10> ==> <uinteger 10> <接尾辞>
          | . <数字 10>+ #* <接尾辞>
          | <数字 10>+ . <数字 10>* #* <接尾辞>
          | <数字 10>+ #+ . #* <接尾辞>
     <uinteger R> ==> <数字 R>+ #*
     <接頭辞 R> ==> <基数 R> <正確性>
          | <正確性> <基数 R>

     <接尾辞> ==> <empty>
          | <指数部マーカ> <符号> <数字 10>+
     <指数部マーカ> ==> e | s | f | d | l
     <符号> ==> <empty>  | + |  -
     <正確性> ==> <empty> | #i | #e
     <基数 2> ==> #b
     <基数 8> ==> #o
     <基数 10> ==> <empty> | #d
     <基数 16> ==> #x
     <数字 2> ==> 0 | 1
     <数字 8> ==> 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
     <数字 10> ==> <数字>
     <数字 16> ==> <数字 10> | a | b | c | d | e | f

外部表現
----

<データ> とは，read 手続き (Input) がパースに成功するものである。 <式> としてパースされる文字列はすべて，<データ> としてもパースされることに注意せよ。

     <データ> ==> <simple datum> | <compound datum>
     <simple datum> ==> <ブーリアン> | <数>
          | <文字> | <文字列> |  <シンボル>
     <シンボル> ==> <識別子>
     <compound datum> ==> <リスト> | <ベクタ>
     <リスト> ==> (<データ>*) | (<データ>+ . <データ>)
          | <abbreviation>
     <abbreviation> ==> <abbrev prefix> <データ>
     <abbrev prefix> ==> ' | ` | , | ,@
     <ベクタ> ==> #(<データ>*)

式
-

     <式> ==> <変数>
          | <リテラル>
          | <手続き呼出し>
          | <λ式>
          | <条件式>
          | <代入>
          | <派生式>

     <リテラル> ==> <quotation> | <self-evaluating>
     <self-evaluating> ==> <ブーリアン> | <数>
          | <文字> | <文字列>
     <quotation> ==> '<データ> | (quote <データ>)
     <手続き呼出し> ==> (<演算子> <オペランド>*)
     <演算子> ==> <式>
     <オペランド> ==> <式>

     <λ式> ==> (lambda <仮引数部> <本体>)
     <仮引数部> ==> (<変数>*) | <変数>
          | (<変数>+ . <変数>)
     <本体> ==> <定義>* <式の列>
     <式の列> ==> <コマンド>* <式>
     <コマンド> ==> <式>

     <条件式> ==> (if <テスト> <帰結部> <代替部>)
     <テスト> ==> <式>
     <帰結部> ==> <式>
     <代替部> ==> <式> | <empty>

     <代入> ==> (set! <変数> <式>)

     <派生式> ==>
           (cond <cond 節>+)
          | (cond <cond 節>* (else <式の列>))
          | (case <式>
             <case 節>+)
          | (case <式>
             <case 節>*
             (else <式の列>))
          | (and <テスト>*)
          | (or <テスト>*)
          | (let (<binding spec>*) <本体>)
          | (let <変数> (<binding spec>*) <本体>)
          | (let* (<binding spec>*) <本体>)
          | (letrec (<binding spec>*) <本体>)
          | (begin <式の列>)
          | (do (<iteration spec>*)
               (<テスト> <式の列>)
             <コマンド>*)
          | (delay <式>)
          | <quasiquotation>

     <cond 節> ==> (<テスト> <式の列>)
          | (<テスト>)
          | (<テスト> => <受取先>)
     <受取先> ==> <式>
     <case 節> ==> ((<データ>*) <式の列>)

     <binding spec> ==> (<変数> <式>)
     <iteration spec> ==> (<変数> <初期値> <ステップ>)
          | (<変数> <初期値>)
     <初期値> ==> <式>
     <ステップ> ==> <式>

準引用
---

準引用式に対する以下の文法は文脈自由ではない。これは無限個の生成規則を生成するためのレシピとして与えられている。 D = 1, 2, 3, ... に対する以下の規則のコピーを想像せよ。 D は入れ子の深さを保持する。

     <quasiquotation> ==> <quasiquotation 1>
     <template 0> ==> <式>
     <quasiquotation D> ==> `<template D>
          | (quasiquote <template D>)
     <template D> ==> <simple datum>
          | <list template D>
          | <vector template D>
          | <unquotation D>
     <list template D> ==> (<template or splice D>*)
          | (<template or splice D>+ . <template D>)
          | '<template D>
          | <quasiquotation D+1>
     <vector template D> ==> #(<template or splice D>*)
     <unquotation D> ==> ,<template D-1>
          | (unquote <template D-1>)
     <template or splice D> ==> <template D>
          | <splicing unquotation D>
     <splicing unquotation D> ==> ,<template D-1>
          | (unquote-splicing <template D-1>)

<quasiquotation> の中で， <list template D> は <unquotation D> または <splicing unquotation D> と解釈がかちあうことがある。 <unquotation> または <splicing unquotation D> としての解釈が優先される。

プログラムと定義
--------

     <プログラム> ==> <command or definition>*
     <command or definition> ==> <コマンド> | <定義>
     <定義> ==> (define <変数> <式>)
          | (define (<変数> <def formals>) <本体>)
          | (begin <定義>*)
     <def formals> ==> <変数>*
          | <変数>+ . <変数>

形式的意味論
======

この節は Scheme の原始式といくつかの組込み手続きに対する形式的な表示的意味論を定める。ここで使われる概念と記法は [STOY77] に記述されている。

     注： 形式的意味論の節は，TeXinfo と互換性のない LaTeX で書かれている。[R4RS] の pp.34--36 を見よ。 [R4RS] はこの文書の原本である。

抽象構文
----

ドメイン等式
------

意味関数
----

補助関数
----

派生式型
====

この節は派生式型に対する書換え規則を与える。これらの規則の適用によって，どんな式も，原始式型 (リテラル，変数，呼出し，lambda，if，set!) だけが出現する意味的に等価な式へと簡約できる。

     (cond (<テスト> <式の列>)
           <節 2> ...)
       ==  (if <テスト>
               (begin <式の列>)
               (cond <節 2> ...))

     (cond (<テスト>)
           <節 2> ...)
       ==  (or <テスト> (cond <節 2> ...))

     (cond (<テスト> => <受取先>)
           <節 2> ...)
       ==  (let ((test-result <テスト>)
                 (thunk2 (lambda () <受取先>))
                 (thunk3 (lambda () (cond <節 2> ...))))
             (if test-result
                 ((thunk2) test-result)
                 (thunk3)))

     (cond (else <式の列>))
       ==  (begin <式の列>)

     (cond)
       ==  <未規定の値を返すなんらかの式>

     (case <キー>
       ((d1 ...) <式の列>)
       ...)
       ==  (let ((key <キー>)
                 (thunk1 (lambda () <式の列>))
                 ...)
             (cond ((<memv> key '(d1 ...)) (thunk1))
                    ...))

     (case <キー>
       ((d1 ...) <式の列>)
       ...
       (else f1 f2 ...))
       ==  (let ((key <キー>)
                 (thunk1 (lambda () <式の列>))
                 ...
                 (elsethunk (lambda () f1 f2 ...)))
             (cond ((<memv> key '(d1 ...)) (thunk1))
                    ...
                   (else (elsethunk))))

ここで <memv> は，memv 手続きへと評価される式とする。

     (and)              ==  #t
     (and <テスト>)      ==  <テスト>
     (and <テスト 1> <テスト 2> ...)
       ==  (let ((x <テスト 1>)
                 (thunk (lambda () (and <テスト 2> ...))))
             (if x (thunk) x))

     (or)               ==  #f
     (or <テスト>)       ==  <テスト>
     (or <テスト 1> <テスト 2> ...)
       ==  (let ((x <テスト 1>)
                 (thunk (lambda () (or <テスト 2> ...))))
             (if x x (thunk)))

     (let ((<変数 1> <初期値 1>) ...)
       <本体>)
       ==  ((lambda (<変数 1> ...) <本体>) <初期値 1> ...)

     (let* () <本体>)
       ==  ((lambda () <本体>))
     (let* ((<変数 1> <初期値 1>)
            (<変数 2> <初期値 2>)
            ...)
       <本体>)
       ==  (let ((<変数 1> <初期値 1>))
             (let* ((<変数 2> <初期値 2>)
                    ...)
               <本体>))

     (letrec ((<変数 1> <初期値 1>)
              ...)
       <本体>)
       ==  (let ((<変数 1> <undefined>)
                 ...)
              (let ((<temp 1> <初期値 1>)
                    ...)
                (set! <変数 1> <temp 1>)
                ...)
              <本体>)

ここで <temp 1>, <temp 2>, ... は，<変数 1>, ... とは別の，元の <初期値> 式で自由な出現をしない変数とする。そして <undefined> は，何かそれを格納するとその格納場所にある値を得ようと試みることがエラーになるようなものを返す式とする (このような式は定義されていないが，この書換え規則の目的のためにそれが存在すると想定する)。展開式のなかの二つめの let 式は，厳密には不必要だが，各 <初期値> 式が任意の順序で評価されるという性質を保存する役目をしている。

     (begin <式の列>)
       ==  ((lambda () <式の列>))

下記の，begin に対するもう一つの展開式は， λ式の本体に複数の式を書けるということを利用していない。いずれの場合でも，これらの規則は <式の列> が定義を含まないときにだけ適用されるということに注意せよ。

     (begin <式>)  ==  <式>
     (begin <コマンド> <式の列>)
       ==  ((lambda (ignore thunk) (thunk))
            <コマンド>
            (lambda () (begin <式の列>)))

下記の，do に対する展開式は，どの <ステップ> も省略されないという想定によって簡単化されている。 <ステップ> が省略された do 式はどれも，対応する <変数> が <ステップ> として現れる等価な do 式で置き換えることができる。

     (do ((<変数 1> <初期値 1> <ステップ 1>)
          ...)
         (<テスト> <式の列>)
       <コマンド 1> ...)
       ==  (letrec ((<loop>
                     (lambda (<変数 1> ...)
                       (if <テスト>
                           (begin <式の列>)
                           (begin <コマンド 1>
                                  ...
                                  (<loop> <ステップ 1> ...))))))
             (<loop> <初期値 1> ...))

ここで <loop> は，<変数 1>, ... とは別の， do 式で自由な出現をしない任意の変数とする。

     (let <変数 0> ((<変数 1> <初期値 1>) ...)
       <本体>)
       ==  ((letrec ((<変数 0> (lambda (<変数 1> ...)
                                  <本体>)))
               <変数 0>)
            <初期値 1> ...)

     (delay <式>)
       ==  (<make-promise> (lambda () <式>))

ここで <make-promise> は，force 手続きに関して適切に振舞うなんらかの手続きへと評価される式とする。 Control featuresを見よ。

注
*

言語変化
====

この節は ``Scheme 報告書 三訂版'' [R3RS] が出版されて以来 Scheme になされてきた変更を列挙する。

  * 実装は Scheme を拡張してもよいが，いかなる予約語の追加もいかなる Scheme の字句規約の横取りもしない構文モードを用意しなければならない。

  * 実装は実装制限の違反を報告してもよい。

  * 空リストが条件式で真とみなされるか偽とみなされるかは，もはや規定されない。Scheme に対する IEEE 規格が空リストを真とみなすことを要求している点は注意すべきである [IEEESCHEME]。

  * boolean?, pair?, symbol?, number?, char?, string?, vector?, および procedure? によって定義される集合は交わらないことが要求される。

  * lambda, let, letrec, および do によって束縛される変数に重複があってはならない。

  * 定義を収めた入れ子の begin 式は，定義の列として扱われる。

  * eqv? 手続きはもはや二つの空文字列または二つの空ベクタについて真であることを要求されない。

  * 数値定数の構文が変更され，そして各構文の暗示する正確性が規定された。

  * 多くの数値手続きの意味論が明確化された。

  * rationalize は２引数に制限され，その仕様が明確化された。

  * number->string 手続きと string->number 手続きは変更された。

  * integer->char は今や正確整数の引数を要求する。

  * force 手続きの仕様は弱められた。以前の仕様は実装不可能だった。

  * 取り消された変数: t, nil

  * 取り消された手続き: approximate, last-pair

  * 追加された手続き: list?, peek-char

  * 必須になった構文: case, and, or, quasiquote

  * 必須になった手続き:

     reverse        char-ci=?        make-string
     max            char-ci<?        string-set!
     min            char-ci>?        string-ci=?
     modulo         char-ci<=?       string-ci<?
     gcd            char-ci>=?       string-ci>?
     lcm            char-alphabetic? string-ci<=?
     floor          char-numeric?    string-ci>=?
     ceiling        char-whitespace? string-append
     truncate       char-lower-case? open-input-file
     round          char-upper-case? open-output-file
     number->string char-upcase      close-input-port
     string->number char-downcase    close-output-port

  * より一般的な個数の引数をとれるように要求された手続き: append, +, *, - (１引数), / (１引数), =, <, >, <=, >=, map, for-each

  * マクロ機能がこの報告書の付録として追加された。

例
*

integrate-system は微分方程式の系

y_k' = f_k(y_1, y_2, ..., y_n), ; k = 1, ..., n

をルンゲ・クッタ法で積分する。

パラメタ system-derivative は，系の状態 (状態変数 y_1, ..., y_n の各値からなるベクタ) を受け取って系の導関数値 (y_1', ..., y_n' の各値) を算出する関数である。パラメタ initial-state は系の初期状態を定める。パラメタ h は積分の刻み幅の初期推測値である。

integrate-system が返す値は，系の状態の無限ストリームである。

     (define integrate-system
       (lambda (system-derivative initial-state h)
         (let ((next (runge-kutta-4 system-derivative h)))
           (letrec ((states
                     (cons initial-state
                           (delay (map-streams next
                                               states)))))
             states))))

runge-kutta-4 は，系の状態から系の導関数値を算出する関数 f を引数とする。 runge-kutta-4 は，系の状態を受け取って新しい系の状態を算出する関数を戻り値とする。

     (define runge-kutta-4
       (lambda (f h)
         (let ((*h (scale-vector h))
               (*2 (scale-vector 2))
               (*1/2 (scale-vector (/ 1 2)))
               (*1/6 (scale-vector (/ 1 6))))
           (lambda (y)
             ;; y is a system state
             (let* ((k0 (*h (f y)))
                    (k1 (*h (f (add-vectors y (*1/2 k0)))))
                    (k2 (*h (f (add-vectors y (*1/2 k1)))))
                    (k3 (*h (f (add-vectors y k2)))))
               (add-vectors y
                 (*1/6 (add-vectors k0
                                    (*2 k1)
                                    (*2 k2)
                                    k3))))))))

     (define elementwise
       (lambda (f)
         (lambda vectors
           (generate-vector
             (vector-length (car vectors))
             (lambda (i)
               (apply f
                      (map (lambda (v) (vector-ref  v i))
                           vectors)))))))

     (define generate-vector
       (lambda (size proc)
         (let ((ans (make-vector size)))
           (letrec ((loop
                     (lambda (i)
                       (cond ((= i size) ans)
                             (else
                              (vector-set! ans i (proc i))
                              (loop (+ i 1)))))))
             (loop 0)))))

     (define add-vectors (elementwise +))

     (define scale-vector
       (lambda (s)
         (elementwise (lambda (x) (* x s)))))

map-streams は map に類似である。これは第１引数 (手続き) を第２引数 (ストリーム) の全要素へ適用する。

     (define map-streams
       (lambda (f s)
         (cons (f (head s))
               (delay (map-streams f (tail s))))))

無限ストリームは，ストリームの第１要素を car が保持し，ストリームの残りをかなえる約束を cdr が保持するペアとして実装される。

     (define head car)
     (define tail
       (lambda (stream) (force (cdr stream))))

下記は，減衰振動をモデル化した系

        d v            v
           C            C
     C (----) = - i  - --
        d t        L   R

        d i
           L
     L (----) = v
        d t      C

の積分での integrate-system の利用例である。

     (define damped-oscillator
       (lambda (R L C)
         (lambda (state)
           (let ((Vc (vector-ref state 0))
                 (Il (vector-ref state 1)))
             (vector (- 0 (+ (/ Vc (* R C)) (/ Il C)))
                     (/ Vc L))))))

     (define the-states
       (integrate-system
          (damped-oscillator 10000 1000 .001)
          '#(1 0)
          .01))

マクロ
***

この付録は，プログラムが新しい派生式型を定義し使用することを可能にする一つの Scheme の拡張を記述する。この拡張を使って定義された派生式型はマクロと呼ばれる。

この拡張を使って導入される派生式型は次の構文をもつ。

     (<キーワード> <データ>*)

ここで <キーワード> は式型を一意的に決定する識別子である。この識別子はマクロの構文キーワード，または単にマクロのキーワードと呼ばれる。 <データ> の個数と構文は式型に依存する。

マクロの各インスタンスは，そのマクロの使用と呼ばれる。あるマクロの使用がより原始的な式へとどのように書き換えられるかを規定する規則の集合，またはより一般的に手続きは，そのマクロの変換子 (transformer) と呼ばれる。

ここで記述される拡張は三つの部分からなる。

  * ある識別子がマクロ・キーワードであることを確立し，それらをマクロ変換子と結合させ，そしてマクロが定義されるスコープを制御するために使われる式の集合

  * 大多数のマクロに対する変換子の記述を容易にする便利なパターン言語

  * パターン言語では表現できないマクロ変換子を書くための両立可能な低水準マクロ機能

この拡張に関しては，予約識別子はない。マクロの構文キーワードが変数束縛を隠蔽することもあれば，ローカル変数の束縛がキーワードの束縛を隠蔽することもある。パターン言語を使って定義されるすべてのマクロは``保健的'' (hygienic) で ``参照透過的'' (referentially transparent) である。つまり，

  * マクロ変換子が識別子 (変数またはキーワード) に対する束縛を書き込むとき，その識別子は，他の識別子との衝突を避けるため，そのスコープ全体で事実上改名される。

  * マクロ変換子が識別子への自由な参照を書き込むとき，その参照は，そのマクロの使用を取り囲んでいるローカルな束縛とは一切関係なく，変換子が規定された地点で見えていた束縛を参照する。

この付録は三つの大きな節に分けられる。第１節は，マクロの導入，つまり識別子のマクロ変換子への束縛，に使われる式と定義を記述する。

第２節はパターン言語を記述する。このパターン言語は，Derived expression typesからの派生式型すべてのマクロ変換子を含め，大多数のマクロ変換子を規定するのに十分である。パターン言語の第一義的な限界は，それが徹頭徹尾保健的であり，したがって陰に隠れて識別子を束縛するようなマクロを表現できないことである。

第３節は，第２節で記述されたパターン言語の実装にも使える低水準なマクロ機能を記述する。この低水準機能は，非保健的なマクロその他の，パターン言語では変換子を記述できないようなマクロを表現することも可能であり，高水準なパターン言語と共存できるより強力な機能の一例として重要である。

この第３節で記述される低水準機能は，第２節で記述されるパターン言語を補完するために設計および実装されたいくつかの低水準機能のうちの一つにすぎない。このような低水準マクロ機能の設計はいまだ一つの活発な研究分野であり，また別の低水準機能の記述が後続の文書で出版されるだろう。

構文キーワードの束縛
==========

define-syntax，let-syntax および letrec-syntax は， define，let および letrec に相当するが，変数を値を収めた場所へと束縛するかわりに，構文キーワードをマクロ変換子へと束縛する。さらに，Internal definitionsで記述された内部定義に相当する define-syntax はない。

根拠：  以下で論ずるように，構文キーワードが予約されていない場合，定義に対する構文とスコープの規則は構文上のあいまいさのもとになる。もし define-syntax が，<本体> の先頭で，内部定義に相当するようなスコープ規則をもって許されていたとしたら，さらにあいまいさが生じただろう。

これらの新しい式型とPattern languageで記述されるパターン言語は， Formal syntaxの BNF を下記の新しい生成規則で増すことによって， Scheme に追加される。これらの生成規則のいくつかで使われている識別子 ... は超記号ではないことに注意せよ。

     <式> ==> <マクロ使用>
          | <マクロ・ブロック>

     <マクロ使用> ==> (<キーワード> <データ>*)
     <キーワード> ==> <識別子>

     <マクロ・ブロック> ==>
           (let-syntax (<構文仕様>*) <本体>)
          | (letrec-syntax (<構文仕様>*) <本体>)
     <構文仕様> ==> (<キーワード> <変換子仕様>)
     <変換子仕様> ==>
           (syntax-rules (<識別子>*) <構文規則>*)
     <構文規則> ==> (<パターン> <テンプレート>)
     <パターン> ==> <パターン識別子>
          | (<パターン>*)
          | (<パターン>+ . <パターン>)
          | (<パターン>* <パターン> <省略符号>)
          | <パターン・データ>
     <パターン・データ> ==> <ベクタ>
          | <文字列>
          | <文字>
          | <ブーリアン>
          | <数>
     <テンプレート> ==> <パターン識別子>
          | (<テンプレート要素>*)
          | (<テンプレート要素>+ . <テンプレート>)
          | <テンプレート・データ>
     <テンプレート要素> ==> <テンプレート>
          | <テンプレート> <省略符号>
     <テンプレート・データ> ==> <パターン・データ>
     <パターン識別子> ==> <... 以外の任意の識別子>
     <省略符号> ==> <識別子 ...>

     <command or definition> ==> <構文定義>
     <構文定義> ==>
           (define-syntax <キーワード> <変換子仕様>)
          | (begin <構文定義>*)

マクロは，定義が許される文脈ならばどこでも定義へと展開してよい。ただし，もし定義が構文キーワードを隠蔽する場合，隠蔽する定義を含むトップ・レベル定義または内部定義のグループ内に，それが実際に定義であるかどうかを決定するためにその構文キーワードの意味を必要とするような定義が存在するか，または，そのグループとそのグループに続く式との境界を決定するためにその構文キーワードの意味が必要ならば，エラーである。たとえば，下記はエラーである。

     (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)))

 -- 構文: let-syntax <束縛部> <本体>

     構文：  <束縛部> の形式は次のとおりとする。

          ((<キーワード> <変換子仕様>) ...)

     各 <キーワード> は識別子であり，各 <変換子仕様> は syntax-rules のインスタンスであり，そして <本体> は１個以上の式からなる列とする。束縛されるキーワードの並びのなかに一つの <キーワード> が複数回現れることはエラーである。

     意味：  <本体> が展開される。ただし，そのときの構文環境は let-syntax 式の構文環境をマクロで拡張して得た構文環境とする。そしてそのマクロはそれぞれ，各 <キーワード> をキーワードとし，指定された各変換子へと束縛されたマクロとする。 <キーワード> のどの束縛も <本体> をその領域とする。

          (let-syntax ((when (syntax-rules ()
                               ((when test stmt1 stmt2 ...)
                                (if test
                                    (begin stmt1
                                           stmt2 ...))))))
            (let ((if #t))
              (when if (set! if 'now))
              if))                    =>  now

          (let ((x 'outer))
            (let-syntax ((m (syntax-rules () ((m) x))))
              (let ((x 'inner))
                (m))))                =>  outer

 -- 構文: letrec-syntax <束縛部> <本体>

     構文：  let-syntax と同じ。

     意味：  <本体> が展開される。ただし，そのときの構文環境は letrec-syntax 式の構文環境をマクロで拡張して得た構文環境とする。そしてそのマクロはそれぞれ，各 <キーワード> をキーワードとし，指定された各変換子へと束縛されたマクロとする。 <キーワード> のどの束縛も <本体> ばかりでなく <束縛部> を領域に含めているから，その変換子は式を，letrec-syntax 式で導入されるマクロを使用した式へと書き換えることができる。

          (letrec-syntax
            ((or (syntax-rules ()
                   ((or) #f)
                   ((or e) e)
                   ((or e1 e2 ...)
                    (let ((temp e1))
                      (if temp
                          temp
                          (or e2 ...)))))))
            (let ((x #f)
                  (y 7)
                  (temp 8)
                  (let odd?)
                  (if even?))
              (or x
                  (let temp)
                  (if y)
                  y)))                =>  7

 -- 構文: define-syntax <キーワード> <変換子仕様>

     構文：  <キーワード> は識別子であり， <変換子仕様> は syntax-rules のインスタンスとする。

     意味：  <キーワード> を指定された変換子に束縛することによって，トップ・レベルの構文環境が拡張される。

          (define-syntax let*
            (syntax-rules ()
              ((let* () body1 body2 ...)
               (let () body1 body2 ...))
              ((let* ((name1 val1) (name2 val2) ...)
                 body1 body2 ...)
               (let ((name1 val1))
                 (let* ((name2 val2) ...)
                   body1 body2 ...)))))

パターン言語
======

 -- 構文: syntax-rules <リテラル部> <構文規則> ...

     構文：  <リテラル部> は識別子の並びであり，各 <構文規則> は次の形式をとるものとする。

          (<パターン> <テンプレート>)

     ここで <パターン> と <テンプレート> は上記の文法にあるとおりである。

     意味：  syntax-rules のインスタンスは，保健的な書換え規則の列を規定することによって，一つの新しいマクロ変換子を作り出す。マクロの使用は，そのマクロのキーワードが結合している変換子を規定する syntax-rules の各 <構文規則> に含まれているパターンに対して照合される。照合は最左の <構文規則> から開始される。マッチするパターンが見つかると，そのマクロ使用はテンプレートに従って保健的に書き換えられる。

     各パターンは，そのマクロを表すキーワードで始まる。このキーワードは照合にはかかわらないし，パターン変数またはリテラル識別子とも見なされない。

     根拠：  キーワードのスコープは，それを被結合マクロ変換子へと束縛する式または構文定義によって決定される。もしキーワードがパターン変数またはリテラル識別子だったならば，そのキーワードが let-syntax で束縛されたのか，それとも letrec-syntax で束縛されたのかに関係なく，そのパターンに続くテンプレートがそのスコープに含まれることになる。

     <構文規則> のパターンに現れる識別子は，それがそのパターンを始めたキーワードでなく，<リテラル部> の並びになく，識別子 ``...'' でもないならば，パターン変数である。パターン変数は任意の入力要素とマッチし，テンプレートのなかで入力要素を参照するために使われる。一つの <パターン> のなかに同じパターン変数が複数回現れることはエラーである。

     <リテラル部> に現れる識別子はリテラル識別子と解釈される。リテラル識別子は入力のなかの対応する部分形式と照合される。入力のなかの部分形式がリテラル識別子とマッチするのは，それが一つの識別子であって，そのマクロ式での出現とマクロ定義での出現がともに同じ字句的束縛をもつか，または二つの識別子が等しくてどちらも字句的束縛をもたないとき，かつそのときに限る。

     部分形式に ... が続くとき，それは０個以上の入力要素とマッチできる。 <リテラル部> に ... が現れることはエラーである。パターンのなかで識別子 ... は，部分パターンの非空な列の最終要素の次に来なければならない。

     より形式的にいえば，入力形式 F がパターン P とマッチするのは，次が成り立つときかつそのときに限る。

       * P がパターン変数である。または

       * P がリテラル識別子であり，F は同じ束縛をもった識別子である。または

       * P がパターン・リスト (P1 ... PN) であり， F は P1 から PN までそれぞれマッチする N 個の形式からなるリストである。または

       * P が仮性パターン・リスト (P1 P2 ... PN . Q) であり， F は P1 から PN までそれぞれマッチする N 個以上の形式からなるリストまたは仮性リストであって，その第 N ``cdr'' が Q にマッチする。または

       * P が (P1 ... PN Q <省略符号>) という形式をとる。ここで <省略符号> は識別子 ... とする。そして F は少なくとも N 要素の真正リストであり，その最初の N 要素がそれぞれ P1 から PN までマッチし，残りの各要素が Q にマッチする。または

       * P がパターン・データであり，F は P と equal? 手続きの意味で等しい。

     マクロ・キーワードの束縛のスコープ内では，そのキーワードをどのパターンともマッチしないような式に使用することはエラーである。

     マクロ使用がそのマッチする <構文規則> のテンプレートに従って書き換えられるとき，テンプレートに出現するパターン変数は，入力でその変数がマッチする部分形式によって置き換えられる。１個以上の識別子 ... を従えた部分パターンに出現するパターン変数は，同じだけの個数の ... を従えた部分テンプレートにだけ存在を許される。出力においてそれらは，入力でそれがマッチする部分形式のすべてによって，指示されたとおりに分配されて，置き換えられる。もし指定されたとおりに出力が形成できないならばエラーである。

     テンプレートには現れるがパターン変数でも識別子 ... でもない識別子は，リテラル識別子として出力に書き込まれる。もしリテラル識別子が自由な識別子として書き込まれるときは，その識別子はその syntax-rules のインスタンスが現れるスコープでの束縛を参照する。もしリテラル識別子が束縛された識別子として書き込まれるときは，その識別子は自由識別子を偶然捕らえてしまわないように事実上改名される。

          (define-syntax let
            (syntax-rules ()
              ((let ((name val) ...) body1 body2 ...)
               ((lambda (name ...) body1 body2 ...)
                val ...))
              ((let tag ((name val) ...) body1 body2 ...)
               ((letrec ((tag (lambda (name ...)
                                body1 body2 ...)))
                  tag)
                val ...))))

          (define-syntax cond
            (syntax-rules (else =>)
              ((cond (else result1 result2 ...))
               (begin result1 result2 ...))
              ((cond (test => result))
               (let ((temp test))
                 (if temp (result temp))))
              ((cond (test => result) clause1 clause2 ...)
               (let ((temp test))
                 (if temp
                     (result temp)
                     (cond clause1 clause2 ...))))
              ((cond (test)) test)
              ((cond (test) clause1 clause2 ...)
               (or test (cond clause1 clause2 ...)))
              ((cond (test result1 result2 ...))
               (if test (begin result1 result2 ...)))
              ((cond (test result1 result2 ...)
                     clause1 clause2 ...)
               (if test
                   (begin result1 result2 ...)
                   (cond clause1 clause2 ...)))))

          (let ((=> #f))
            (cond (#t => 'ok)))       =>  ok

     最後の例はエラーではない。なぜならローカル変数 => は，その使用が cond の変換子が検索するトップ・レベルの識別子 => の使用とは別になるように，事実上改名されるからである。つまり，最後の例は，無効な手続き呼出しに終わることになる

          (let ((=> #f))
            (let ((temp #t))
              (if temp ('ok temp))))

     へと展開されるのではなく，むしろ次のように展開される。

          (let ((=> #f))
            (if #t (begin => 'ok)))

両立可能な低水準マクロ機能
=============

syntax-rules が定めるパターン言語はマクロ変換子を規定するための好ましい方法だが，より複雑なマクロ変換子を規定するために別の低水準機能が定められてもよい。実際，syntax-rules それ自身，この節で記述される低水準機能を使ったマクロとして定義され得る。

ここで記述される低水準マクロ機能は，quote に相当する新しい構文キーワードとして syntax を導入し，そして <変換子仕様> が任意の式であることを許す。これは次の二つの生成規則を前述のFormal syntaxとBinding syntactic keywordsの生成規則へ追加することによって成し遂げられる。

     <式> ==> (syntax <データ>)
     <変換子仕様> ==> <式>

低水準マクロのシステムは更にまた次の手続きを追加する。

     unwrap-syntax          identifier->symbol
     identifier?            generate-identifier
     free-identifier=?      construct-identifier
     bound-identifier=?

プログラムの評価は二つの論理的ステップで進行する。まずプログラムがマクロ展開によって中間言語へ変換され，次にそのマクロ展開の結果が評価される。この過程の第２段階を評価過程全体と区別する必要があるときは，この段階のことを ``実行'' (execution) と呼ぶ。

字句的であれ大域的であれ，構文定義は，識別子をその束縛のスコープ内でキーワードとして取り扱われるようにする。そういったキーワードは変換子と結合される。そしてその変換子は，syntax-rules のパターン言語を使って陰に，または以下で記述される低水準機能を使って陽に，造られ得る。

変換子仕様はマクロ展開の段階で完全に評価されなければならないから，その評価が行われる環境を規定することが必要である。変換子仕様は，プログラムが展開される環境と同じ環境で展開されるが，プログラムが実行される環境とは別の環境で実行される。この実行環境の違いは，グローバル変数の参照と代入の解決にとってのみ重要である。これ以降，変換子が実行される環境を標準変換子環境と呼び，そしてそれは標準 Scheme 環境であるとする。

保健的マクロ展開の仕事の一部は識別子参照を解決することだから述べるが，変換子がプログラムと同じ環境で展開されるという事実は，プログラムでの識別子束縛が変換子内での識別子使用を隠蔽し得ることを意味する。プログラムでの変数束縛は変換子の実行時には入手不可能だから，変換子がそれらを参照または代入することはエラーである。しかし，キーワード束縛は展開のあいだ入手可能だから，プログラムから字句的に可視なキーワード束縛を，変換子でのマクロ使用で使ってもよい。

マクロ使用に出会った時は，そのマクロ・キーワードと結合しているマクロ変換子が，そのマクロ式の表現へ適用される。マクロ変換子が返した結果が元の式と置き換わり，そしてもう一度展開される。したがってマクロ展開はそれ自身マクロ使用であっても，またマクロ使用を含んでいてもよい。

マクロ変換子へ渡される構文表現は，表現されている形式の構造とその形式が含む識別子の束縛についての情報をカプセル化している。これらの構文オブジェクトは，以下に記述する手続きを使ってトラバースし調べることができる。変換子の出力は，普通の Scheme リスト・コンストラクタを使い，入力の断片を新しい構文構造と組み合わせることによって形成することができる。

 -- 構文: syntax <データ>

     構文：  <データ> は Scheme オブジェクトの外部表現ならなんでもよい。

     意味：  syntax は quote の構文的な相当物である。これは <データ> の構文表現を造る。構文表現は，変換子への引数と同じく， <データ> に含まれる識別子に対する束縛についての情報を含んでいる。 syntax が導入する識別子に対する束縛は，最も近く字句的に可視な束縛である。変換子が導入する変数とキーワードはすべて syntax で造られたものでなければならない。変換手続きの出力にシンボルを書き込むことは，もしそのシンボルが，クォートされたデータの一部になるのではないならば，エラーである。

          (symbol? (syntax x))        => #f

          (let-syntax ((car (lambda (x) (syntax car))))
            ((car) '(0)))             => 0

          (let-syntax
            ((quote-quote
              (lambda (x) (list (syntax quote) 'quote))))
            (quote-quote))            => quote

          (let-syntax
            ((quote-quote
              (lambda (x) (list 'quote 'quote))))
            (quote-quote))            => エラー

     二つめの quote-quote 例がエラーに終わっているのは，２個の生のシンボルが出力に書き込まれているからである。一つめの quote-quote 例のクォートされた quote がエラーを起こさないのは，それがクォートされたデータになるからである。

          (let-syntax ((quote-me
                        (lambda (x)
                          (list (syntax quote) x))))
            (quote-me please))        => (quote-me please)

          (let ((x 0))
            (let-syntax ((alpha (lambda (e) (syntax x))))
              (alpha)))               => 0

          (let ((x 0))
            (let-syntax ((alpha (lambda (x) (syntax x))))
              (alpha)))               => エラー

          (let-syntax ((alpha
                        (let-syntax ((beta
                                      (syntax-rules ()
                                        ((beta) 0))))
                          (lambda (x) (syntax (beta))))))
            (alpha))                  => エラー

     最後の二つの例がエラーなのは，どちらの場合も，字句的に束縛された識別子がその束縛のスコープの外に置かれるからである。第１の場合では，変数 x がそのスコープの外に置かれる。第２の場合では，キーワード beta がそのスコープの外に置かれる。

          (let-syntax ((alpha (syntax-rules ()
                                ((alpha) 0))))
            (let-syntax ((beta (lambda (x) (alpha))))
              (beta)))                => 0

          (let ((list 0))
            (let-syntax ((alpha (lambda (x) (list 0))))
              (alpha)))               => エラー

     最後の例がエラーなのは，変換子での list への参照が， list に対する字句的束縛によって隠蔽されているからである。展開過程はプログラムの実行とは別だから，変換子がプログラム変数を参照することはできない。他方，その前の例がエラーでないのは，プログラム中のキーワードに対する定義は展開時に存在するからである。

     注：  (syntax <データ>) と (quasisyntax <データ>) に対してそれぞれ #'<データ> と #`<データ> が適切な略記法として提案されている。ここで quasisyntax は，この付録では記述されていないが， quasiquote が quote に対して負う関係と同じ関係を syntax に対して負うものとする。

 -- 手続き: identifier? syntax-object

     もし SYNTAX-OBJECT が識別子を表現しているならば #t を返し，そうでなければ #f を返す。

          (identifier? (syntax x))    => #t
          (identifier? (quote x))     => #f
          (identifier? 3)             => #f

 -- 手続き: unwrap-syntax syntax-object

     もし SYNTAX-OBJECT が識別子ならば，それがそのまま返される。そうでなければ unwrap-syntax は，SYNTAX-OBJECT の最外構造を，SYNTAX-OBJECT と同じ外部表現のデータ・オブジェクトへと変換する。結果は一つの識別子か，car と cdr が構文オブジェクトであるペアか，要素が構文オブジェクトであるベクタか，空リストか，文字列か，ブーリアンか，または数である。

          (identifier? (unwrap-syntax (syntax x)))
                                      => #t
          (identifier? (car (unwrap-syntax (syntax (x)))))
                                      => #t
          (unwrap-syntax (cdr (unwrap-syntax (syntax (x)))))
                                      => ()

 -- 手続き: free-identifier=? id1 id2

     もし ID1 と ID2 の元々の出現が同じ束縛をもっていれば #t を返し，そうでなければ #f を返す。 free-identifier=? は，たとえば cond 節の中の else など，変換子への引数の中のリテラル識別子を探すために使われる。 syntax-rules に対するマクロ定義は，入力の中のリテラルを探すために free-identifier=? を使うことになるだろう。

          (free-identifier=? (syntax x) (syntax x))
                                      => #t
          (free-identifier=? (syntax x) (syntax y))
                                      => #f

          (let ((x (syntax x)))
            (free-identifier=? x (syntax x)))
                                      => #f

          (let-syntax
            ((alpha
              (lambda (x)
                (free-identifier=? (car (unwrap-syntax x))
                                   (syntax alpha)))))
            (alpha))                  => #f

          (letrec-syntax
            ((alpha
              (lambda (x)
                (free-identifier=? (car (unwrap-syntax x))
                                   (syntax alpha)))))
            (alpha))                  => #t

 -- 手続き: bound-identifier=? id1 id2

     もし二つの識別子 ID1 と ID2 のうちの一つに対する束縛が，もう一つの自由な参照を隠蔽していれば #t を返し，そうでなければ #f を返す。もし二つの識別子が展開過程の別々の段階で導入されたのならば，それらは bound-identifier=? であることなしに free-identifier=? であり得る。 bound-identifier=? は，たとえば，束縛変数並びの中から重複した識別子を検出するために使うことができる。 syntax-rules のマクロ定義は，入力パターンからのパターン変数を出力テンプレートにおいて探すために bound-identifier=? を使うことになるだろう。

          (bound-identifier=? (syntax x) (syntax x))
                                      => #t

          (letrec-syntax
            ((alpha
              (lambda (x)
                (bound-identifier=? (car (unwrap-syntax x))
                                    (syntax alpha)))))
            (alpha))                  => #f

 -- 手続き: identifier->symbol id

     ID の元々の名前を表現するシンボルを返す。 identifier->symbol は，リテラルの文脈に現れる識別子，つまりクォートされた構造の中に現れる識別子を調べるために使われる。

          (symbol? (identifier->symbol (syntax x)))
                                      => #t
          (identifier->symbol (syntax x))
                                      => x

 -- 手続き: generate-identifier
 -- 手続き: generate-identifier symbol

     新しい識別子を返す。 generate-identifier への省略可能な引数は，結果となる識別子のシンボルとしての名前を指定する。引数が与えられていないときの名前は未規定である。

     generate-identifier は，束縛識別子を変換子の出力の中に導入するために使われる。導入される束縛識別子は自動的に改名されるから， generate-identifier は，不定個数の識別子をマクロによって生成しなければならないときに，それら導入される識別子を区別するためだけに必要である。

     generate-identifier への省略可能な引数は，結果となる識別子のシンボルとしての名前を指定する。引数が与えられていないときの名前は未規定である。手続き identifier->symbol は識別子のシンボルとしての名前を明らかにする。

          (identifier->symbol (generate-identifier 'x))
                                      => x

          (bound-identifier=? (generate-identifier 'x)
                              (generate-identifier 'x))
                                      => #f

          (define-syntax set*!
            ; (set*! (<識別子> <式>) ...)
            (lambda (x)
              (letrec
                ((unwrap-exp
                  (lambda (x)
                    (let ((x (unwrap-syntax x)))
                      (if (pair? x)
                          (cons (car x)
                                (unwrap-exp (cdr x)))
                          x)))))
                (let ((sets (map unwrap-exp
                                 (cdr (unwrap-exp x)))))
                  (let ((ids (map car sets))
                        (vals (map cadr sets))
                        (temps (map (lambda (x)
                                      (generate-identifier))
                                    sets)))
                    `(,(syntax let) ,(map list temps vals)
                      ,@(map (lambda (id temp)
                               `(,(syntax set!) ,id ,temp))
                             ids
                             temps)
                      #f))))))

 -- 手続き: construct-identifier id symbol

     あたかも識別子 ID が導入された地点で導入されたかのように振舞う識別子を，造って返す。 SYMBOL がその識別子の名前となる。

     construct-identifier は，あたかも式の中に暗黙のうちに存在していたかのように振舞う識別子を造ることによって，保健性の裏をかくために使われる。たとえば，構造体を定義するマクロの変換子は，構造体の欄をアクセスする関数の名前がマクロの使用の中に明示的に現れていなくても，その関数名が構造体名と欄名から組み立てられるならば，その関数名を組み立てることができる。もしそのような関数名に対する束縛を，保健的な変換子が導入したとしても，その場合，その関数名は自動的に改名されてしまうから，そうやって導入した束縛は，入力の中に存在しそして導入した束縛のスコープの中に入れているつもりだったその関数名への参照を，捕捉し損なうことになる。

     もう一つの例は exit を暗黙のうちに束縛するマクロである。

          (define-syntax loop-until-exit
            (lambda (x)
              (let ((exit (construct-identifier
                           (car (unwrap-syntax x))
                           'exit))
                    (body (car (unwrap-syntax
                                (cdr (unwrap-syntax x))))))
                `(,(syntax call-with-current-continuation)
                  (,(syntax lambda)
                   (,exit)
                   (,(syntax letrec)
                    ((,(syntax loop)
                      (,(syntax lambda) ()
                         ,body
                         (,(syntax loop)))))
                    (,(syntax loop))))))))

          (let ((x 0) (y 1000))
            (loop-until-exit
             (if (positive? y)
                 (begin (set! x (+ x 3))
                        (set! y (- y 1)))
                 (exit x))))          => 3000

謝辞
==

この付録で記述された拡張は，ブロック構造をもったプログラミング言語のためにかつて提案された最も洗練されたマクロ機能である。主なアイディアは，Dan Friedman [HYGIENIC]の指導の下で書かれた Eugene Kohlbecker の保健的マクロ展開に関する博士論文[KOHLBECKER86]と，構文クロージャに関する Alan Bawden と Jonathan Rees による労作[BAWDEN88] に由来する。パターン指向のマクロ機能は，Kent Dybvig による extend-syntax の非保健的な実装によって普及した[DYBVIG87]。

1988 年の Snowbird でのこの報告書の著者たちの会合で， Bawden, Rees, Dybvig, Bob Hieb からなるマクロ委員会は， extend-syntax に似た，しかし構文クロージャに基づいた，保健的なマクロ機能の開発をゆだねられた。 Chris Hanson はプロトタイプを実装し，その経験をもとに論文を書いた。そこで彼は，構文クロージャに基づく実装では，いくつかの識別子の構文的な役割を決定しておかなければ，テキストのパターン・マッチングに基づくマクロ展開はそれらの識別子の役割をはっきりさせられない，ということを指摘した。 William Clinger は Kohlbecker のアルゴリズムがこの決定を遅延する技法になることに気づき，Kohlbecker のアルゴリズムのより効率的なバージョンを提案した。 Pavel Curtis は参照透過なローカル・マクロを提案した。 Rees は構文環境を修正版の Kohlbecker のアルゴリズムとマージし，そしてそれ全体を２回実装した[MACROSTHATWORK]。

Dybvig と Hieb は上に記述された低水準マクロ機能を実装した。最近になって Hanson と Bawden は，また別の低水準マクロ機能を得るために構文クロージャを拡張した。マクロ委員会は，特定の低水準機能を支持しているわけではなく，この付録で記述された高水準パターン言語と両立可能な低水準機能という一般的な概念を支持している。

このほか何人もの人々が，マクロに関する何年にもわたる作業によって貢献してきた。 Hal Abelson は，この報告書をマクロについての付録まで引き延ばすことで貢献した。

参考文献
****

[Abelson88]
     Harold Abelson and Gerald Jay Sussman. Lisp: a langauge for stratified design. BYTE 13(2):207--218, February 1988.

[SICP]
     Harold Abelson and Gerald Jay Sussman with Julie Sussman. Structure and Interpretation of Computer Programs. MIT Press, Cambridge, 1985.

[Adams88]
     Norman Adams and Jonathan Rees. Object-oriented programming in Scheme. In Proceedings of the 1988 Conference on Lisp and Functional Programming, pages 277--288, August 1988.

[Bartley86]
     David H. Bartley and John C. Jensen. The implementation of PC Scheme. In Proceedings of the 1986 ACM Conference on Lisp and Functional Programming, pages 86--93.

[Scheme81]
     John Batali, Edmund Goodhue, Chris Hanson, Howie Shrobe, Richard M. Stallman, and Gerald Jay Sussman. The Scheme-81 architecture---system and chip. In Proceedings, Conference on Advanced Research in VLSI, pages 69--77. Paul Penfield, Jr., editor. Artech House, 610 Washington Street, Dedham MA, 1982.

[bawden88]
     Alan Bawden and Jonathan Rees. Syntactic closures. In Proceedings of the 1988 ACM Symposium on Lisp and Functional Programming, pages 86--95.

[Clinger84]
     William Clinger. The Scheme 311 compiler: an exercise in denotational semantics. In Conference Record of the 1984 ACM Symposium on Lisp and Functional Programming, pages 356--364.

[RRRS]
     William Clinger, editor. The revised revised report on Scheme, or an uncommon Lisp. MIT Artificial Intelligence Memo 848, August 1985. Also published as Computer Science Department Technical Report 174, Indiana University, June 1985.

[Clinger88]
     William Clinger. Semantics of Scheme. BYTE 13(2):221--227, February 1988.

[howtoread]
     William Clinger. How to read floating point numbers accurately. In Proceedings of the ACM SIGPLAN '90 Conference on Programming Language Design and Implementation, pages 92--101. Proceedings published as SIGPLAN Notices 25(6), June 1990.

[Clinger85]
     William Clinger, Daniel P. Friedman, and Mitchell Wand. A scheme for a higher-level semantic algebra. In Algebraic Methods in Semantics, pages 237--250. J. Reynolds, M. Nivat, editor. Cambridge University Press, 1985.

[Clinger88b]
     William Clinger, Anne Hartheimer, and Eric Ost. Implementation strategies for continuations. In Proceedings of the 1988 ACM Conference on Lisp and Functional Programming, pages 124--131.

[macrosthatwork]
     William Clinger and Jonathan Rees. Macros that work. In Proceedings of the 1991 ACM Conference on Principles of Programming Languages, pages 155--162.

[Curtis90]
     Pavel Curtis and James Rauen. A module system for Scheme. In Proceedings of the 1990 ACM Conference on Lisp and Functional Programming, June 1990.

[Dybvig87]
     R. Kent Dybvig. The Scheme Programming Language. Prentice-Hall, 1987.

[Dybvig86]
     R. Kent Dybvig and Daniel P. Friedman and Christopher T. Haynes. Expansion-passing style: a general macro mechanism. Lisp and Symbolic Computation 1(1):53--76, June 1988.

[Dybvig88]
     R. Kent Dybvig and Robert Hieb. A variable-arity procedural interface. In Proceedings of the 1988 ACM Symposium on Lisp and Functional Programming, pages 106--115.

[Dybvig88]
     R. Kent Dybvig and Robert Hieb. Engines from continuations. Journal of Computer Languages 14(2), pages 109--123, 1989.

[Dybvig88]
     R. Kent Dybvig and Robert Hieb. Continuations and concurrency. In Proceedings of the Second ACM SIGPLAN Notices Symposium on Principles and Practice of Parallel Programming, pages 128--136, March 1990.

[Eisenberg85]
     Michael A. Eisenberg. Bochser: an integrated Scheme programming system. MIT Laboratory for Computer Science Technical Report 349, October 1985.

[Eisenberg88]
     Michael Eisenberg. Harold Abelson, editor. Programming In Scheme. Scientific Press, Redwood City, California, 1988.

[Eisenberg90]
     Michael Eisenberg, with William Clinger and Anne Hartheimer. Harold Abelson, editor. Programming In MacScheme. Scientific Press, San Francisco, 1990.

[Feeley86]
     Marc Feeley. Deux approches `a l'implantation du language Scheme. M.Sc. thesis, De'partement d'Informatique et de Recherche Ope'rationelle, University of Montreal, May 1986.

[Feeley87]
     Marc Feeley and Guy LaPalme. Using closures for code generation. Journal of Computer Languages 12(1):47--66, 1987.

[Feeley90]
     Marc Feeley and James Miller. A parallel virtual machine for efficient Scheme compilation. In Proceedings of the 1990 ACM Conference on Lisp and Functional Programming, June 1990.

[Felleisen87b]
     Matthias Felleisen. Reflections on Landin's J-Operator: a partly historical note. Journal of Computer Languages 12(3/4):197--207, 1987.

[Felleisen86b]
     Matthias Felleisen and Daniel P. Friedman. Control operators, the SECD-machine, and the lambda-calculus. In 3rd Working Conference on the Formal Description of Programming Concepts, pages 193--219, August 1986.

[Felleisen86c]
     Matthias Felleisen and Daniel P. Friedman. A closer look at export and import statements. Journal of Computer Languages 11(1):29--37, 1986.

[Felleisen87]
     Matthias Felleisen and Daniel P. Friedman. A calculus for assignments in higher-order languages. In Conference Record of the 14th Annual ACM Symposium on Principles of Programming Languages, pages 314--345, January 1987.

[Felleisen87d]
     Matthias Felleisen and Daniel P. Friedman. A reduction semantics for imperative higher-order languages. In Lecture Notes in Computer Science, Parallel Architectures and Languages Europe 259:206--223, 1987. De Bakker, Nijman and Treleaven, editors. Springer-Verlag, Berlin.

[Felleisen86]
     Matthias Felleisen, Daniel P. Friedman, Eugene Kohlbecker, and Bruce Duba. Reasoning with continuations. In Proceedings of the Symposium on Logic in Computer Science, pages 131--141. IEEE Computer Society Press, Washington DC, 1986.

[Felleisen87c]
     Matthias Felleisen, Daniel P. Friedman, Eugene E. Kohlbecker, and Bruce Duba. A syntactic theory of sequential control. Theoretical Computer Science 52:205--237, 1987.

[Felleisen88]
     Matthias Felleisen, Mitchell Wand, Daniel P. Friedman, and Bruce Duba. Abstract continuations: a mathematical semantics for handling functional jumps. In Proceedings of the 1988 ACM Symposium on Lisp and Functional Programming, July 1988.

[Scheme311]
     Carol Fessenden, William Clinger, Daniel P. Friedman, and Christopher Haynes. Scheme 311 version 4 reference manual. Indiana University Computer Science Technical Report 137, February 1983. Superseded by [SCHEME84].

[Franco90]
     John Franco and Daniel P. Friedman. Towards a facility for lexically scoped, dynamic mutual recursion in Scheme. Journal of Computer Languages 15(1):55--64, 1990.

[Lisper]
     Daniel P. Friedman and Matthias Felleisen. The Little LISPer. Science Research Associates, second edition 1986.

[littlelisper]
     Daniel P. Friedman and Matthias Felleisen. The Little LISPer. MIT Press, 1987.

[Friedman85]
     Daniel P. Friedman and Christopher T. Haynes. Constraining control. In Proceedings of the Twelfth Annual Symposium on Principles of Programming Languages, pages 245--254. ACM, January 1985.

[Friedman84]
     Daniel P. Friedman, Christopher T. Haynes, and Eugene Kohlbecker. Programming with continuations. In Program Transformation and Programming Environments, pages 263--274. P. Pepper, editor. Springer-Verlag, 1984.

[Scheme84]
     D. Friedman, C. Haynes, E. Kohlbecker, and M. Wand. Scheme 84 interim reference manual. Indiana University Computer Science Technical Report 153, January 1985.

[Friedman84b]
     Daniel P. Friedman and Mitchell Wand. Reification: reflection without metaphysics. In Conference Record of the 1984 ACM Symposium on Lisp and Functional Programming, pages 348--355.

[Haynes86]
     Christopher T. Haynes. Logic continuations. In Proceedings of the Third International Conference on Logic Programming, pages 671--685. Springer-Verlag, July 1986.

[Engines]
     Christopher T. Haynes and Daniel P. Friedman. Engines build process abstractions. In Conference Record of the 1984 ACM Symposium on Lisp and Functional Programming, pages 18--24.

[Haynes87b]
     Christopher T. Haynes and Daniel P. Friedman. Abstracting timed preemption with engines. Journal of Computer Languages 12(2):109--121, 1987.

[Haynes87a]
     Christopher T. Haynes and Daniel P. Friedman. Embedding continuations in procedural objects. ACM Transactions on Programming Languages and Systems 9(4):582--598, October 1987.

[Haynes86]
     Christopher T. Haynes and Daniel P. Friedman and Mitchell Wand. Obtaining coroutines with continuations. Journal of Computer Languages 11(3/4):143--153, 1986.

[Henderson82]
     Peter Henderson. Functional geometry. In Conference Record of the 1982 ACM Symposium on Lisp and Functional Programming, pages 179--187.

[Dybvig88]
     Robert Hieb, R. Kent Dybvig, and Carl Bruggeman. Representing control in the presence of first-class continuations. In Proceedings of the ACM SIGPLAN '90 Conference on Programming Language Design and Implementation, pages 66--77, June 1990. Proceedings published as SIGPLAN Notices 25(6), June 1990.

[IEEE]
     IEEE Standard 754-1985.  IEEE Standard for Binary Floating-Point Arithmetic.  IEEE, New York, 1985.

[IEEEScheme]
     IEEE Standard 1178-1990.  IEEE Standard for the Scheme Programming Language.  IEEE, New York, 1991.

[Kohlbecker86]
     Eugene Edmund Kohlbecker Jr. Syntactic Extensions in the Programming Language Lisp. PhD thesis, Indiana University, August 1986.

[hygienic]
     Eugene E. Kohlbecker, Daniel P. Friedman, Matthias Felleisen, and Bruce Duba. Hygienic macro expansion. In Proceedings of the 1986 ACM Conference on Lisp and Functional Programming, pages 151--161.

[Kranz86]
     David Kranz, Richard Kelsey, Jonathan Rees, Paul Hudak, James Philbin, and Norman Adams. Orbit: An optimizing compiler for Scheme. In Proceedings of the SIGPLAN '86 Symposium on Compiler Construction, pages 219--233. ACM, June 1986. Proceedings published as SIGPLAN Notices 21(7), July 1986.

[Kranz88]
     David Kranz. Orbit: An optimizing compiler for Scheme. PhD thesis, Yale University, 1988.

[Landin65]
     Peter Landin. A correspondence between Algol 60 and Church's lambda notation: Part I. Communications of the ACM 8(2):89--101, February 1965.

[McDermott80]
     Drew McDermott. An efficient environment allocation scheme in an interpreter for a lexically-scoped lisp. In Conference Record of the 1980 Lisp Conference, pages 154--162. Proceedings reprinted by ACM.

[MITScheme]
     MIT Department of Electrical Engineering and Computer Science. Scheme manual, seventh edition. September 1984.

[Muchnick80]
     Steven S. Muchnick and Uwe F. Pleban. A semantic comparison of Lisp and Scheme. In Conference Record of the 1980 Lisp Conference, pages 56--64. Proceedings reprinted by ACM.

[Naur63]
     Peter Naur et al. Revised report on the algorithmic language Algol 60. Communications of the ACM 6(1):1--17, January 1963.

[Penfield81]
     Paul Penfield, Jr. Principal values and branch cuts in complex APL. In APL '81 Conference Proceedings, pages 248--256. ACM SIGAPL, San Francisco, September 1981. Proceedings published as APL Quote Quad 12(1), ACM, September 1981.

[Pitman85]
     Kent M. Pitman. Exceptional situations in Lisp. MIT Artificial Intelligence Laboratory Working Paper 268, February 1985.

[Pitman83]
     Kent M. Pitman. The revised MacLisp manual (Saturday evening edition). MIT Laboratory for Computer Science Technical Report 295, May 1983.

[Pitman80]
     Kent M. Pitman. Special forms in Lisp. In Conference Record of the 1980 Lisp Conference, pages 179--187. Proceedings reprinted by ACM.

[Plebanthesis]
     Uwe F. Pleban. A Denotational Approach to Flow Analysis and Optimization of Scheme, A Dialect of Lisp. PhD thesis, University of Kansas, 1980.

[Rees89]
     Jonathan A. Rees. Modular Macros. M.S. thesis, MIT, May 1989.

[Rees82]
     Jonathan A. Rees and Norman I. Adams IV. T: A dialect of Lisp or, lambda: The ultimate software tool. In Conference Record of the 1982 ACM Symposium on Lisp and Functional Programming, pages 114--122.

[Rees84]
     Jonathan A. Rees, Norman I. Adams IV, and James R. Meehan. The T manual, fourth edition. Yale University Computer Science Department, January 1984.

[R3RS]
     Jonathan Rees and William Clinger, editors. The revised(3) report on the algorithmic language Scheme. In ACM SIGPLAN Notices 21(12), pages 37--79, December 1986.

[R4RS]
     William Clinger and Jonathan Rees, Editors. Revised(4) Report on the Algorithmic Language Scheme. In ACM Lisp Pointers IV (July-September 1991).

[Reynolds72]
     John Reynolds. Definitional interpreters for higher order programming languages. In ACM Conference Proceedings, pages 717--740. ACM, 1972.

[Rozas84]
     Guillermo J. Rozas. Liar, an Algol-like compiler for Scheme. S. B. thesis, MIT Department of Electrical Engineering and Computer Science, January 1984.

[schflow]
     Olin Shivers. Control flow analysis in Scheme. Proceedings of the SIGPLAN 1988 Conference on Programming Language Design and Implementation, pages 164--174. Proceedings published as SIGPLAN Notices 23(7), July 1988.

[Sitaram90]
     Dorai Sitaram and Matthias Felleisen. Control delimiters and their hierarchies. Lisp and Symbolic Computation 3(1):67--99, January 1990.

[Smith84]
     Brian C. Smith. Reflection and semantics in a procedural language. MIT Laboratory for Computer Science Technical Report 272, January 1982.

[Springer89]
     George Springer and Daniel P. Friedman. Scheme and the Art of Programming. MIT Press and McGraw-Hill, 1989.

[Srivastava85]
     Amitabh Srivastava, Don Oxley, and Aditya Srivastava. An(other) integration of logic and functional programming. In Proceedings of the Symposium on Logic Programming, pages 254--260. IEEE, 1985.

[Stallman80]
     Richard M. Stallman. Phantom stacks---if you look too hard, they aren't there. MIT Artificial Intelligence Memo 556, July 1980.

[Declarative]
     Guy Lewis Steele Jr. Lambda, the ultimate declarative. MIT Artificial Intelligence Memo 379, November 1976.

[Debunking]
     Guy Lewis Steele Jr. Debunking the ``expensive procedure call'' myth, or procedure call implementations considered harmful, or lambda, the ultimate GOTO. In ACM Conference Proceedings, pages 153--162. ACM, 1977.

[Macaroni]
     Guy Lewis Steele Jr. Macaroni is better than spaghetti. In Proceedings of the Symposium on Artificial Intelligence and Programming Languages, pages 60--66. These proceedings were published as a special joint issue of SIGPLAN Notices 12(8) and SIGART Newsletter 64, August 1977.

[Rabbit]
     Guy Lewis Steele Jr. Rabbit: a compiler for Scheme. MIT Artificial Intelligence Laboratory Technical Report 474, May 1978.

[renamegoto]
     Guy Lewis Steele Jr. Compiler optimization based on viewing LAMBDA as RENAME + GOTO. In AI: An MIT Perspective. Patrick Henry Winston Richard Henry Brown, editor. MIT Press, 1980.

[CLoverview]
     Guy Lewis Steele Jr. An overview of Common Lisp. In Conference Record of the 1982 ACM Symposium on Lisp and Functional Programming, pages 98--107.

[CLtL]
     Guy Lewis Steele Jr. Common Lisp: The Language. Digital Press, Burlington MA, 1984.

[Imperative]
     Guy Lewis Steele Jr. and Gerald Jay Sussman. Lambda, the ultimate imperative. MIT Artificial Intelligence Memo 353, March 1976.

[Scheme78]
     Guy Lewis Steele Jr. and Gerald Jay Sussman. The revised report on Scheme, a dialect of Lisp. MIT Artificial Intelligence Memo 452, January 1978.

[TAOTI]
     Guy Lewis Steele Jr. and Gerald Jay Sussman. The art of the interpreter, or the modularity complex (parts zero, one, and two). MIT Artificial Intelligence Memo 453, May 1978.

[DOALBP]
     Guy Lewis Steele Jr. and Gerald Jay Sussman. Design of a Lisp-based processor. Communications of the ACM 23(11):628--645, November 1980.

[Dream]
     Guy Lewis Steele Jr. and Gerald Jay Sussman. The dream of a lifetime: a lazy variable extent mechanism. In Conference Record of the 1980 Lisp Conference, pages 163--172. Proceedings reprinted by ACM.

[howtoprint]
     Guy Lewis Steele Jr. and Jon L White. How to print floating point numbers accurately. In Proceedings of the ACM SIGPLAN '90 Conference on Programming Language Design and Implementation, pages 112--126. Proceedings published as SIGPLAN Notices 25(6), June 1990.

[Sussman82]
     Gerald Jay Sussman. Lisp, programming and implementation. In Functional Programming and its Applications. Darlington, Henderson, Turner, editor. Cambridge University Press, 1982.

[Scheme75]
     Gerald Jay Sussman and Guy Lewis Steele Jr. Scheme: an interpreter for extended lambda calculus. MIT Artificial Intelligence Memo 349, December 1975.

[Scheme79]
     Gerald Jay Sussman, Jack Holloway, Guy Lewis Steele Jr., and Alan Bell. Scheme-79---Lisp on a chip. IEEE Computer 14(7):10--21, July 1981.

[Stoy77]
     Joseph E. Stoy. Denotational Semantics: The Scott-Strachey Approach to Programming Language Theory. MIT Press, Cambridge, 1977.

[TI85]
     Texas Instruments, Inc. TI Scheme Language Reference Manual. Preliminary version 1.0, November 1985.

[Vegdahl89]
     Steven R. Vegdahl and Uwe F. Pleban. The runtime environment for Screme, a Scheme implementation on the 88000. In Proceedings of the Third International Conference on Architectural Support for Programming Languages and Operating Systems, pages 172--182, April 1989.

[Wand78]
     Mitchell Wand. Continuation-based program transformation strategies. Journal of the ACM 27(1):174--180, 1978.

[Wand80]
     Mitchell Wand. Continuation-based multiprocessing. In Conference Record of the 1980 Lisp Conference, pages 19--28. Proceedings available from ACM.

[Wand86]
     Mitchell Wand. Finding the source of type errors. In Conference Record of the Thirteenth Annual Symposium on Principles of Programming Languages, pages 38--43, 1986.

[tower]
     Mitchell Wand. The mystery of the tower revealed: a non-reflective description of the reflective tower. In Proceedings of the 1986 ACM Symposium on LISP and Functional Programming, pages 298--307, August 1986.

[Wand78]
     Mitchell Wand and Daniel P. Friedman. Compiling lambda expressions using continuations and factorizations. Journal of Computer Languages 3:241--263, 1978.

[Wand88]
     Mitchell Wand and Daniel P. Friedman. The mystery of the tower revealed: a non-reflective description of the reflective tower. In Meta-Level Architectures and Reflection, pages 111--134. P. Maes and D. Nardi, editor. Elsevier Sci. Publishers B.V. (North Holland), 1988.

索引
**