8. 式言語 式言語は,IEEE Scheme規格及び"Schemeに関する報告 改定4版(R4RS)"が定義するプログラム言語Schemeに基づく。次の規定は,その定義に基づく。 式言語とプログラム言語Schemeとの相違点を,次に示す。 (1) 式言語は,プログラム言語Schemeの関数的で副作用のない部分集合だけを用いている。副作用がなければ意味がない機能(例えばbegin)は,排除した。 (2) データ型vectorは用いない。 (3) 文字オブジェクトは,文字符号ではなく,名前によって一意に識別する。 (4) プログラム言語SchemeのASCII文字集合への依存性を排除した。 (5) データ型numberは,数値に次元の概念を加えたもっと一般的なデータ型quantityの下位型としている。 (6) 継続を用いない。 (7) R4RSの幾つかのオプション機能は用いない。 (8) 手続きgcd(最大公約数)及び手続きlcm(最小公倍数)は用いない。 (9) キーワード引数を提供する。 さらにDSSSLは,プログラム言語Schemeの定義が実装依存としている選択肢のうち,特定のもの要求する。 中核式言語と呼ぶ式言語の部分集合を,8.6で定義する。 8.1 式言語の概要 プログラム言語Algolと同様に,式言語は静的スコープをもつ。どの変数の使用も,字句上で明らかな変数の束縛に関連する。 式言語は,明示的な型と対照をなす暗黙の型をもつ。型は,変数ではなく,オブジェクトとも呼ぶ値に関連する。暗黙の型をもつ言語を,弱い型付け言語又は動的型付け言語と呼ぶことがある。暗黙の型をもつ他の言語には,プログラム言語APL,プログラム言語Snobol及びプログラム言語Lispの他の方言がある。明示的な型をもつ言語を,強い型付け言語又は静的型付け言語と呼ぶことがある。明示的な型をもつ言語には,プログラム言語Algol 60,プログラム言語Pascal及びプログラム言語Cがある。 手続きを含む計算の過程で生成するすべてのオブジェクトは,無限の有効期間をもつ。式言語のオブジェクトが破壊されることはない。実装が記憶容量不足になることもない。その理由は,オブジェクトが後の計算に全く必要でないことが明らかである場合には,そのオブジェクトの占める記憶を再要求できることにある。ほとんどのオブジェクトが無限の有効期間をもつ他の言語には,プログラム言語APL及び他のプログラム言語Lispの方言がある。 実装は,正しく末尾再帰を扱えなければならない。これによって,反復計算が構文上再帰的な手続きを用いて記述されている場合にも,一定空間での反復計算として実行が可能になる。したがって,末尾再帰的な実装においては,反復は通常の手続き呼び出しを用いて表現でき,その結果,特別な反復構成子は構文糖としての意味をもつにすぎない。 手続きは,それ自体でオブジェクトになる。手続きは動的に生成され,データ構造の中に記憶され,手続きの結果として返される。この特徴をもつ他の言語に,プログラム言語Common Lisp及びプログラム言語MLがある。 手続きに対する引数は,常に値で渡される。これは,手続きが評価結果を必要とするか否かに関わらず,手続きが制御を得る前に実際の引数式が評価されることを意味する。常に引数を値で渡す他の言語に,プログラム言語ML,プログラム言語C及びプログラム言語APLの三つがある。これは,プログラム言語Haskellの遅延評価の意味又はプログラム言語Algol 60の名前呼び出しの意味とは異なる。それらにおいては,手続きが値を必要としなければ,引数式は評価されない。 多くのプログラム言語Lispの方言と同様に,式言語は,式及び他のデータのすべてをかっこでくくった前置記法を用いる。つまり,式言語の構文は,データ用の副言語を生成する。 8.2 基本概念 8.2.1 変数及び領域 構文で予約されていない識別子は,すべて変数として使ってよい。変数は,値に名前を付ける。値に名前を付けた変数は,値に束縛されたという。ある点で有効なすべての束縛の集合は,その点で有効な環境と呼ぶ。変数に束縛された値を,変数の値と呼ぶ。 ある種の式は,変数を新しい値に束縛するために用いる。束縛構成子の最も基本的なものは,lambda式となる。他のすべての束縛構成子は,lambda式によって説明できる。その他の束縛構成子には,let式,let*式及びletrec式がある。 プログラム言語Algol及びプログラム言語Pascalに類似し,プログラム言語Common Lisp以外の他の多くのLisp方言と異なり,式言語は,ブロック構造をもつ静的スコープの言語である。変数が式に束縛されるそれぞれの場所に,束縛が有効である式テキストの領域が対応する。この領域は,束縛を確立する特定の束縛構成子によって決定される。例えば,束縛がlambda式によって確立される場合,その領域はlambda式全体となる。変数のすべての参照は,その使用を含む領域の最も内側で確立した変数の束縛を参照する。変数の使用を含む領域の変数の束縛が無い場合には,その使用は,最上位環境があればそこでの変数の束縛を参照する。識別のための束縛が無い場合には,未束縛と呼ぶ。 8.2.2 真及び偽 どの式言語値も,条件判定のための型booleanのオブジェクトとして利用できる。#f以外のどの値も,その判定において真と解釈する。この規格は,'真'という語を使って真と解釈するすべての値を指し,'偽'という語を使って#fを指す。 8.2.3 外部表現 式言語及びプログラム言語Lispにおいての重要な概念に,オブジェクトの外部表現を文字列で表すことがある。例えば,整数28の外部表現は,文字列'28'となり,整数8及び13から成るリストの外部表現は,文字列'(8 13)'となる。 あるオブジェクトの外部表現は,必ずしも一意である必要はない。前段落のリストは,'( 08 13 )'及び'(8. (13.()))'と表現してもよい。 多くのオブジェクトは外部表現をもつが,手続きなどの幾つかのオブジェクトは外部表現をもたない。 外部表現は,対応するオブジェクトを得るために,式の中に書いてもよい。 外部表現は,この規格が規定するプロセスの間の通信に利用してもよい。 さまざまな種類のオブジェクトの外部表現の構文には,オブジェクト操作のための基本手続きの記述を伴う。 8.2.4 型の独立性 次の判定を二つ以上同時に満たすオブジェクトは存在しない。 (1) boolean? (2) symbol? (3) keyword? (4) char? (5) pair? (6) quantity? (7) string? (8) procedure? これらの記述は,データ型boolean,データ型pair,データ型symbol,データ型keyword,データ型quantity,データ型char(又はcharacter),データ型string及びデータ型procudureを定義する。 8.3 式 式は,変数参照,リテラル,手続き呼出し,条件判定などの値を返す構成子とする。 [16] expression = primitive-expression | derived-expression 式の型は,基本型又は派生型に分類できる。基本型は,変数及び手続き呼出しを含む。派生型は,基本型ではなく,その意味を基本構成子によって説明できる。派生型は厳密な意味では冗長だが,共通の利用類型をとらえており,便利な短縮形として提供される。 8.3.1 基本型の式 [17] primitive-expression = variable-reference | literal | procedure-call | lambda-expression | conditional 8.3.1.1 変数参照  [18] variable-reference = variable 変数から成る式を,変数参照とする。変数参照の値は,変数が束縛される値とする。束縛のない変数を参照することは,エラーとする。 例5: (define x 28) x ==> 28 [19] variable = identifier [20] syntactic-keyword = expression-keyword | else | =>| define [21] expression-keyword = quote | lambda | if | cond | and | or | case | let | let*| letrec | quasiquote | unquote | unquote-splicing 構文変数syntactic-keywordに属さない識別子は,変数として利用できる。DSSSLは,前掲のものに加えて識別子を,構文予約語として確保してよい。 8.3.1.2 リテラル  [22] literal = quotation | self-evaluating [23] quotation = 'datum | (quote datum) (quote datum)は,評価の結果datumとなる。 [24] datum = simple-datum | list [25] simple-datum = boolean | number | character | string | symbol | keyword | named-constant | glyph-identifier 構文変数datumは,式言語オブジェクトのどの外部表現であってもよい。この記法は,式中のリテラル定数を含むために用いる。グリフ識別子は,構文style-language-body内だけで許可される。 例6: (quote a) ==> a (quote (+ 1 2)) ==> (+ 1 2) (quote datum)は短縮して'datumとしてよい。すべての点でこの二つの記法は,等価とする。 例7: 'a ==> a '() ==> () '(+ 1 2) ==> (+ 1 2) '(quote a) ==> (quote a) ''a ==> (quote a) [26] self-evaluating = boolean | number | character | string | keyword | named-constant | glyph-identifier 型booleanのオブジェクト定数,数値定数,文字定数,文字列定数,キーワード,名前付き定数及びグリフ識別子は,評価の結果それ自体になり,構文quotationを使用する必要はない。 例8: '"abc" ==> "abc"' "abc" ==> "abc"' '145932 ==> 145932 145932 ==> 145932 '#t ==> #t #t ==> #t abc: ==> abc: 'abc: ==> abc: 8.3.1.3 手続き呼出し  [27] procedure-call = (operator operand*) [28] operator = expression [29] operand = expression 手続き呼出しは,呼出し対象の手続き式及びその手続きに渡す引数を単純にかっこで囲むことで表記する。式operator及び式operandは評価され,結果の手続きに結果の引数が渡される。 例9: (+ 3 4) ==> 7 ((if #f + *) 3 4) ==> 12 複数個の式operator又は式operandがエラーを通知する場合,どちらのエラーを利用者に報告するかは,処理系依存とする。 多くの手続きは,初期環境の変数値として利用できる。例えば,前述の式の中の加算手続き及び乗算手続きは,変数+及び変数*の値となる。新しい手続きはlambda式を評価して作成する。 手続きは,組合わせとも呼ばれる。 備考 他のLisp方言とは対照的に,式operator及び式operandは,常に同一評価規則によって評価される。 8.3.1.4 lambda式  [30] lambda-expression = (lambda (formal-argument-list) body) lambda式は,評価の結果手続きとなる。lambda式を評価した時点で有効な環境は,手続きの一部として記憶される。手続きが,後で実際の引数を伴って呼ばれた場合,lambda式を評価した時点の環境は,形式的引数リスト内の変数の対応する実際の値への束縛によって拡張し,その拡張された環境内でlambda式の本体が評価される。lambda式の本体の評価結果は,手続き呼出しの結果として返される。 例10: (lambda (x) (+ x x)) ==> a procedure ((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 [31] formal-argument-list = required-formal-argument*     (#!optional optional-formal-argument*)?     (#!rest rest-formal-argument)?     (#!key keyword-formal-argument*)? [32] required-formal-argument = variable [33] optional-formal-argument = variable | ((variable initializer)) [34] rest-formal-argument = variable [35] keyword-formal-argument = variable | ((variable initializer)) [36] initializer = expression 実引数リストに対して手続きを適用したとき,形式的引数及び実引数は,左から右へ次のとおりに処理する。 (1) 構文 required-formal-argument 内の変数は, 最初の実引数から始めて連続する実引数に束縛される。必す(須)の引数より実引数が少ない場合,エラーとなる。 (2) 次に,構文optional-formal-argument内の変数は,残っている実引数に束縛される。オプションの引数より少ない実引数が残っており,構文initializerが指定されている場合にはその評価結果を,その他の場合には#fを,変数に束縛する。構文initializerは,それ以前の引数すべてを束縛した環境において評価する。 (3) 構文rest-formal-argumentがある場合,残ったすべての実引数のリストに束縛される。これら残りの実引数は,構文keyword-formal-argumentに束縛される資格をもつ。構文rest-formal-argumentがなく,構文keyword-formal-argumentもない場合,残りの実引数があればエラーとなる。 (4) #!key が構文 formal-argument-list の中で指定された場合,偶数個の実引数が残っていなければならない。これらは一連の対として解釈される。そこでは,各対の最初のメンバがキーワードであって,引数名を指定する。第二のメンバはそれに対応する値となる。対の最初の要素がキーワードでない場合,エラーとなる。引数名が構文keyword-formal-argumentの変数名と同じでなく,しかも構文rest-formal-argumentが存在しなければ,エラーとなる。同一引数名が実引数のリストの中で1回より多く出現した場合,最初の値を使用する。特定の構文keyword-formal-argumentのための実引数がなく,構文initializerが指定されている場合には,変数はその初期化子を評価した結果に束縛され,その他の場合には,変数は#fに束縛される。構文initializerは,それ以前のすべての形式的引数が束縛されている環境において評価する。 備考 備考 変換言語又はスタイル言語の構文formal-argument-list内での#!keyの利用は,機能keywordを必要とする。 変数が,構文formal-argument-listの中で1回より多く現れる場合,エラーとする。 例11: ((lambda (#!rest x) x) 3 4 5 6) ==> (3 4 5 6) ((lambda (x y #!rest z) z) 3 4 5 6) ==> (5 6) ((lambda (x y #!optional z #!rest r #!key i (j 1)) (list x y z i: i j: j)) 3 4 5 i: 6 i: 7) ==> (3 4 5 i: 6 j: 1) 8.3.1.5 条件式 [37] conditional = (if test consequent alternate) [38] test = expression [39] consequent = expression [40] alternate = expression 式conditionalは,次のとおりに評価する。まず式testを評価する。それが真であれば,式consequentを評価し,その値を返す。その他の場合は,式alternativeを評価し,その値を返す。 例12: (if (> 3 2) 'yes 'no) ==> yes (if (> 2 3) 'yes 'no) ==> no (if (> 3 2) (- 3 2) (+ 3 2)) ==> 1 8.3.2 派生式の型 [41] derived-expression = cond-expression | case-expression | and-expression | or-expression |      binding-expression | named-let | quasiquotation 8.3.2.1 cond式 [42] cond-expression = (cond cond-clause+) | (cond cond-clause* (else expression)) [43] cond-clause = (test expression) | ( test ) | (test => recipient ) [44] recipient = expression cond式は,連続する各節cond-clauseの式testを,その式の一つが真となるまで,順に評価する。一つの式testを真になると,節cond-clauseにおける式の評価結果は,cond式全体の結果として返される。選択した節cond-clauseが式testだけを含む場合,式testの値が結果として返される。節cond-clauseが式receipientを含む場合は,式receipientを評価される。その値は,一つの引数をもつ手続きでなければならない。この手続きは,式testの値に対して呼び出される。すべての式testが偽となり,節elseがない場合には,エラーが通知される。節elseがあれば,その式を評価した結果を返す。 例13: (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 8.3.2.2 case式 [45] case-expression = (case key case-clause+ ) | (case key case-clause* (else expression)) [46] key = expression [47] case-clause = (( datum* ) expression ) 節case-clauseに記述するすべてのデータdatumは別個のデータでなければならない。case式は次のとおりに評価する。式keyを評価し,その結果を各データdatumと比較する。式keyを評価した結果が(equal?の意味で)datumに等しい場合には,対応する節case-clauseの式を評価した結果が,case式の結果として返される。式keyを評価した結果が各データdatumと異なり,節elseがある場合には,その式を評価した結果を,case式の結果とし,その他の場合にはエラーが通知される。 例14: (case (* 2 3) ((2 3 5 7) 'prime) ((1 4 6 8 9) 'composite)) ==> composite (case (car '(c d)) ((a e i o u) 'vowel) ((w y) 'semivowel) (else 'consonant)) ==> consonant 8.3.2.3 And式 [48] and-expression = (and test*) 式testは左から右に評価する。式testの偽となる最初の式の値が返される。その場合,残りの式は評価されない。すべての式が真となる場合,最後の式の値が返される。式testがなければ,#tが返される。 例15: (and (= 2 2) (> 2 1)) ==> #t (and (= 2 2) (< 2 1)) ==> #f (and 1 2 'c '(f g)) ==> (f g) (and) ==> #t 8.3.2.4 Or式 [49] or-expression = (or test*) 式testは左から右に評価する。真となる最初の式の値が返される。その場合,残りの式はどれも評価されない。すべての式が偽となる場合,最後の式の値が返される。式がない場合には,#fが返される。 例16: (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) 8.3.2.5 束縛構成子式 [50] binding-expression = let-expression | let*-expression | letrec-expression 三つの束縛構成子let,let*及びletrecは,プログラム言語Algol 60に類似するブロック構造を式言語に与える。三つの構成子の構文は同一であるが,構成子がその変数束縛のために設定する領域が異なる。let式においては,すべての変数が束縛される前に初期値が計算される。let*式においては,束縛及び評価は連続して実行される。letrec式においては,初期値が計算されている間においてもすべての束縛は有効であり,したがって相互に再帰的な定義をすることができる。 [51] let-expression = (let bindings body) [52] bindings = (binding-spec*) [53] binding-spec = (variable init) [54] init = expression 変数が,節bindingの中で複数回出現することはエラーとする。let式の評価は,次のとおりに行う。節initを現環境において評価し,変数variableをその結果に束縛する。その結果の拡張環境でbodyを評価した結果を返す。変数vaeiableの各束縛の領域は,式bodyとなる。 (let ((x 2) (y 3)) (* x y)) ==> 6 (let ((x 2) (y 3)) (let ((x 7) (z (+ x y))) (* z x))) ==> 35 名前付きlet式も参照のこと。 [55] let*-expression = (let* bindings body) let*式は,式letと同様だが,束縛を左から右に順に行い,節binding-specが示す束縛の領域は,let*式のその部分から節binding-specの終りまでを含む。したがって,第二の束縛は最初の束縛が見える状態で行われ,以降同様となる。 例18: (let* ((x 2) (y 3)) (let* ((x 7) (z (+ x y))) (* z x))) ==> 70 [56] letrec-expression = (letrec bindings body) 節binding-specにおける各変数variableは,対応する式initを評価した結果に束縛され,拡張環境で式bodyを評価した結果が返される。式initは,拡張環境で評価される。節binding-specにおける変数variableの各束縛は,letrec式を全体をその領域とし,相互に再帰的な手続きを定義することを可能にする。式initの評価がどの変数variableの値を参照しても,エラーとする。最も一般的なletrec式の利用形態においては,すべての式initはlambda式であり,この制約は自動的に満たされる。 例19: (letrec ((even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (odd? (lambda (n) (if (zero? n) #f (even? (- n 1)))))) (even? 88)) ==> #t 8.3.2.6 名前つきlet [57] named-let = (let variable ( binding-spec* ) body ) 名前付きlet式は,通常のlet式と同じ構文及びセマンティクスをもつが,節body内において,形式的引数が名前付きlet式の束縛する変数となり,その節bodyが式named-letの節bodyとなる手続きに,変数variableが束縛される。したがって,節bodyの実行を,変数variableによって命名された手続きを呼び出すことによって,繰返してもよい。 例20: (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)) 8.3.2.7 クアジクォート 次に示すクアジクォートの構文は文脈依存になっている。これは無限個の生成規則の構成方法を示している。次の規則において,D=1, 2, 3, ...と入れ子の深さに追随して複製を作ると想定する。 [58] quasiquotation = quasiquotation_1 [59] template_0 = expression [60] quasiquotation_D = `template_D| (quasiquote template_D) [61] template_D = simple-datum | list-template_D| unquotation_D [62] list-template_D = (template-or-splice_D*) | (template-or-splice_D+ . template_D) | 'template_D| quasiquotation_D+1 [63] unquotation_D = ,template_D-1 | (unquote template_D-1) [64] template-or-splice_D = template_D| splicing-unquotation_D [65] splicing-unquotation_D = ,@template_D-1 | (unquote-splicing template_D-1) 節quasiquotationにおいては,節list-template_Dが,節unquotation_D又は節splicing-unquotqtion_Dのいずれかと混同されることがある。節unquotation_D又は節splicing-unquotqtion_Dとしての解釈を優先する。 quasiquote式を使うと,必要な構造のすべてではないがほとんどが既知である場合に,リスト構造の構成が便利となる。構文templateの中にカンマがなければ,`templateの評価結果は'templateの評価結果と等価となる。しかしtemplateの中にカンマがあれば,カンマに続く式は評価され(アンクォートされ),その結果が構造の中にカンマ及び式に代わって入る。カンマの直後にat記号(@)がある場合には,続く式は評価の結果リストとなる。リストの開きかっこ及び閉じかっこは除去され,リストの要素が,カンマat記号式列の位置に挿入される。 例21: `(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) quasiquote式は,入れ子にしてもよい。置換えは,最も外側の逆引用符と同じ入れ子レベルに出現するアンクォートの構成要素でだけ行われる。入れ子レベルは,連続する各quasiquotationの内側で1だけ増加し,各unquotationの内側で1だけ減少する。 例22: `(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) 式`template_D及び式(quasiquote template_D)の記法は,すべての点で同一とする。式,expressionは式(unquote expression)と同一であり,式,@expressionは式(unquote-splicing expression)と同一とする。 例: (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のどれかが,構文templateの中の前述とは異なる位置に現れると,予測できない振舞いが起きるかもしれない。 8.4 定義 [66] definition = variable-definition | procedure-definition 定義は,二つの形式をとることができる。 [67] variable-definition = (define variable expression) この構文を基本型の式とする。 [68] procedure-definition = (define ( variable formal-argument-list ) body ) この形式は,次の定義と等価とする。 (define variable (lambda (variable formal-argument-list) body)). 式の中に現れない定義を,最上位定義と呼ぶ。次の最上位定義は,最上位環境において式expressionを評価し,最上位環境内において変数を評価結果に束縛する。 (define variable expression) 例24: (define add3 (lambda (x) (+ x 3))) (add3 3) ==> 6 (define first car) (first '(1 2)) ==> 1 任意の処理指定部分内において,複数個の最上位定義を用いて同一の変数を定義してはならない。処理指定部分内の変数の最上位定義は,以前の処理指定部分において最上位定義されている場合に無視する。7.1を参照のこと。 最上位定義内の式expressionは,式expressionを評価することによって参照される可能性のあるすべての最上位変数が定義されるまで,評価してはならない。 備考 lambda式の評価は,その中で自由変数を参照しないので,この制約が相互再帰的手続きの定義を妨げることはない。 最上位定義内に出現するすべての式が,この制約を保ったまま評価できない場合にはエラーとする。 実装組み込みの変数の定義は,最上位定義によって置換してよい。 代わりとなる定義はその変数への参照すべてにおいて使用される。参照が,最初の最上位定義を含む処理指定部に先行する部分で起きる場合にでも使用する。 備考 この規則は実装にとって簡単ではない。しかし,適合DSSSL指定の意味を変えずに,規格に組み込み手続きを将来の版の追加可能となる。 [69] body = definition* expression 定義は,構文bodyの先頭でも出現してよい。これらを内部定義と呼ぶ。内部定義で定義した変数は,その構文bodyに固有のものとなる。その生存期間は構文body全体となる。例を次にあげる。 (let ((x 5)) (define foo (lambda (y) (bar x y))) (define bar (lambda (a b) (+ (* a b) a))) (foo (+ x 3))) ==> 45 内部定義を含む構文bodyは,常に同等のletrec式に書き換えることができる。例えば,上に例示したlet式は次の式に等しい。 (let ((x 5)) (letrec ((foo (lambda (y) (bar x y))) (bar (lambda (a b) (+ (* a b) a)))) (foo (+ x 3)))) 同等のletrec式だけについて言えば,定義中の変数の値を参照することなく,構文body内の各内部定義の式は評価可能でなければならない。 8.5 標準手続き 式言語の組込み手続きについて,8.5が記述する。初期(又は`最上位')環境は,便利な値に束縛された多くの変数で始まる。その多くは,データを操作する基本手続きとする。例えば,変数absは,数値の絶対値を計算する引数が一つの手続きに束縛され,変数+は,合計を計算する手続きに束縛される。 手続きに,扱うことを規定されていない型の引数が渡されることはエラーとする。 8.5.1 論理型 [70] boolean = #t | #f 真及び偽を示す標準の論理オブジェクトは,#t及び#fと記す。しかし,実際に重要なのは,条件式(if,cond,and,or)がどのオブジェクトを真又は偽として扱うかにある。`真の値'(又は単に`真'ともいう)という句は,条件式によって真として扱われる任意のオブジェクトを意味し,`偽の値'(又は`偽')という句は,条件式によって偽として扱われる任意のオブジェクトを意味する。 すべての標準値の中で#fだけを,条件式中で偽として解釈する。#fを除くすべての標準値(#t,対,空リスト,シンボル,文字列及び手続きから成る)は,真と解釈する。 備考 他のLisp方言に慣れたプログラマは,式言語が#f及び空リストのいずれもが,シンボルnilとは区別されていることに注意する必要がある。 論理定数は評価の結果それ自体になり,式の中でクォートする必要はない。 例25: #t ==> #t #f ==> #f '#f ==> #f 8.5.1.1 否定 (not obj) 手続きnotは,引数objが偽であれば#tを返し,その他の場合には#fを返す。 例26: (not #t) ==> #f (not 3) ==> #f (not (list 3)) ==> #f (not #f) ==> #t (not '()) ==> #f (not (list)) ==> #f (not 'nil) ==> #f 8.5.1.2 論理型判定 (boolean? obj) 手続きboolean?は,引数objが#t又は#fのどちらかであれば#tを返し,その他の場合には#fを返す。 例27: (boolean? #f) ==> #t (boolean? 0) ==> #f (boolean? '()) ==> #f 8.5.2 等価 (equal? obj1 obj2) 手続きequal?は,オブジェクトの等価関係を定義する。引数obj1及び引数obj2を同一オブジェクトとみなす場合に#tを返し,その他の場合には#fを返す。外部表現をもつオブジェクトについては,その外部表現が同一であるとき,二つのオブジェクトを同一とする。引数obj1及び引数obj2のそれぞれが,型boolean,型symbol,型char,型pair,型quantity又は型stringであれば,手続きequal?は次の場合に#tを返す。 (1) 引数obj1及び引数obj2が,共に#tであるか共に#fである場合。 (2) 引数obj1及び引数obj2が,共にシンボルであって次を満たす場合。 (string=? (symbol->string obj1) (symbol->string obj2)) ==> #t (3) 引数obj1及び引数obj2が,共に数であり,= の意味で数値的に等しく,どちらも正確値であるか又はどちらも不正確値の場合。 (4) 引数obj1及び引数obj2が,共に文字列であり,手続きstring=?にしたがって同一文字列の場合。 (5) 引数obj1及び引数obj2が,共に文字であり,手続きchar=?にしたがって同一文字の場合。 (6) 引数obj1及び引数obj2が,共に空リストの場合。 (7) 引数obj1及び引数obj2が,共に対であって,しかも引数obj1のcar部と引数obj2のcar部がequal?であって,さらに引数obj1のcdr部と引数obj2のcdr部がequal?の場合。 引数obj1及び引数obj2の一方が手続きであって,他方がそうでない場合には,equal?は#fを返す。引数obj1及び引数obj2の両方が手続きである場合には,引数obj1及び引数obj2がある引数に関して異なる値を返す場合にequal?は#fを返し,そうでない場合#t又は#fのどちらかを返す。 備考 換言すると,手続きの等価性は十分には定義されない。 8.5.3 対及びリスト 対(点対ともいう)は,歴史的な理由でcar部又はcdr部と呼ぶ二つの部分をもつ記憶構造とする。対は,手続きconsによって生成される。car部及びcdr部は,手続きcar及び手続きcdrによって参照される。対は,主としてリストを表すために用いる。リストは,空リスト又はcdr部がリストの対として再帰的に定義してもよい。さらに厳密にいうと,リストの集合は,次の最小集合Xとして定義される。 (1) 空リストは集合Xに含まれる。 (2) listがXに含まれるとき,listをcdr部に含むすべての対もまたXに含まれる。 リストの要素列とは,リストを構成する連続する対のcar部のオブジェクト列とする。例えば,2要素リストは,対のcar部が第一要素であり,対のcdr部が対であって,その対のcar部が第二要素であって,その対のcdr部が空リストとなる。リストの長さは,要素の個数とし,要素の個数は対の個数と同じになる。 空リストは,対ではなく,特殊なオブジェクトであってそれ自体の型をもつ。それは要素をもたず,その長さは0である。 備考 この定義は,すべてのリストは有限の長さをもち,空リストによって終結することを示す。 [71] list = (datum*) | (datum+ . datum ) | abbreviation 対の最も一般的な記法(外部表現)は`点'記法であって,(c1 . c2)の場合にはc1をcar部の値,c2をcdr部の値とする。例えば,(4 . 5)は,car部が4でcdr部が5である対とする。(4 . 5)は,対の外部表現であり,評価の結果対になる式ではないことに注意。 リストに関しては,もっと合理的な記法を使ってもよい。つまりリストの要素を単にかっこで囲み,スペースで分離する。空リストは,()と書く。 例えば (a b c d e)  及び (a . (b . (c . (d . (e . ()))))) は,シンボルのリストであって等価な記法となる。 空リストで終わっていない対の連鎖は,不適リストと呼ぶ。不適リストはリストでないことに注意されたい。不適リストを表現するために,リスト及び点付き記法を組合わせてもよい。 (a b c . d) は,次と等価とする。 (a . (b . (c . d))) 与えられた対がリストであるかどうかは,cdr部に何が記録されているかに依存する。 [72] abbreviation = abbrev-prefix datum [73] abbrev-prefix = '| ` | , | ,@ リテラル式内で,記述形式'datum,記述形式`datum,記述形式,datum及び記述形式,@datumは,二つの要素をもつリストを意味し,第一の要素がそれぞれシンボルquote,シンボルquasiquote,シンボルunquote及びシンボルunquote-splicingを示す。第二の要素は,どの場合もdatumとなる。この規約は任意の式及び指定の一部をリストとして表現可能とするためにサポートする。つまり,式言語の構文に従う場合,すべての式expressionはまたdatumでもあり,要素体系transformation-language-bodyはdatumの列となる。 8.5.3.1 対型判定 (pair? obj) 引数objが対であれば#tを返し,その他の場合は#fを返す。 例28: (pair? '(a . b)) ==> #t (pair? '(a b c)) ==> #t (pair? '()) ==> #f 8.5.3.2 対構成手続き (cons obj1 obj2) car部が引数obj1であり,cdr部が引数obj2である対を返す。 例29: (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) 8.5.3.3 手続きcar (car pair) 引数pairのcar部の内容を返す。空リストのcarをとることはエラーとなることに注意されたい。 例30: (car '(a b c)) ==> a (car '((a) b c d)) ==> (a) (car '(1 . 2)) ==> 1 (car '()) ==> error 8.5.3.4 手続きcdr (cdr pair) 引数pairのcdr部の内容を返す。空リストのcdrをとることはエラーとなることに注意されたい。 例31: (cdr '((a) b c d)) ==> (b c d) (cdr '(1 . 2)) ==> 2 (cdr '()) ==> error 8.5.3.5 c...r手続き (caar pair) (cadr pair) (caaar pair) (caadr pair) (cadar pair) (caddr pair) (cdaar pair) (cdadr pair) (cddar pair) (cdddr pair) (caaaar pair) (caaadr pair) (caadar pair) (caaddr pair) (cadaar pair) (cadadr pair) (caddar pair) (cadddr pair) (cdaaar pair) (cdaadr pair) (cdadar pair) (cdaddr pair) (cddaar pair) (cddadr pair) (cdddar pair) (cddddr pair) これらの手続きは,car及びcdrの複合とする。ここで,例えばcaddrは,次式によって定義できる。 (define caddr (lambda (x) (car (cdr (cdr x))))). 四つの深さまでの任意の複合が用意されている。これらの手続きは,全部で28個ある。 8.5.3.6 空リスト型判定 (null? obj) 引数objが空リストであれば#tを返し,その他の場合には#fを返す。 8.5.3.7 リスト型判定 (list? obj) 引数objがリストであれば#tを返し,その他の場合には#fを返す。定義に従うと,すべてのリストは,有限の長さをもち,空リストによって終結する。 例32: (list? '(a b c)) ==> #t (list? '()) ==> #t (list? '(a . b)) ==> #f 8.5.3.8 リスト構成 (list obj ...) 引数を要素とするリストを返す。 例33: (list 'a (+ 3 4) 'c) ==> (a 7 c) (list) ==> () 8.5.3.9 リスト長 (length list) リストの長さを返す。 例34: (length '(a b c)) ==> 3 (length '(a (b) (c d e))) ==> 3 (length '()) ==> 0 8.5.3.10 リスト連結 (append list ...) 最初の引数listの要素に続き,他の引数listの要素を含むリストを返す。 例35: (append '(x) '(y)) ==> (x y) (append '(a) '(b c d)) ==> (a b c d) (append '(a (b)) '((c))) ==> (a (b) (c)) 最後の引数は実際にはオブジェクトであってよい。最後の引数が適切なリストでないと,不適リストとなる。 例36: (append '(a b) '(c . d)) ==> (a b c . d) (append '() 'a) ==> a 8.5.3.11 リスト反転 (reverse list) listの要素を逆順に構成したリストを返す。 例37: (reverse '(a b c)) ==> (c b a) (reverse '(a (b c) d (e (f)))) ==> ((e (f)) d (b c) a) 8.5.3.12 部分リスト抽出 (list-tail list k) 最初のk個の要素を無視して得られたlistの部分リストを返す。list-tailは,次式によって定義できる。 (define list-tail (lambda (x k) (if (zero? k) x (list-tail (cdr x) (- k 1))))) 8.5.3.13 リスト参照 (list-ref list k) listのk番めの要素を返す。これは,(list-tail list k)のcar部と同じとなる。 例38: (list-ref '(a b c d) 2) ==> c (list-ref '(a b c d) (inexact->exact (round 1.8))) ==> c 8.5.3.14 リスト要素 (member obj list) car部が引数objに等しくなる最初の部分リストを返す。ここで,部分リストとは引数kをリストの長さ未満とした場合に,式(list-tail list k)が返す空でないリストとする。引数objが引数list内で出現しない場合には,(空リストではなく)#fを返す。 例39: (member 'a '(a b c)) ==> (a b c) (member 'b '(a b c)) ==> (b c) (member 'a '(b c d)) ==> #f 8.5.3.15 関連リスト (assoc obj alist) 引数alist('association list'を意味する)は,対のリストとする。この手続きは,引数alist内の対であって,その対のcar部が引数objと手続きequal?の意味において等しい場合に,その対を返す。引数alist内の対すべてにおいて,そのcar部が引数objと等しくない場合,(空リストではなく)#fを返す。 例40: (define e '((a 1) (b 2) (c 3)))(assoc 'a e) ==> (a 1) (assoc 'b e) ==> (b 2)(assoc 'd e) ==> #f 備考 通常,これらを判定として使用するが,手続きmember,手続きassocはその名前に疑問符をもたない。これは,これらの手続きが単に#t, #fではなく有用な値を返すことによる。 8.5.4 シンボル シンボルは,2つのシンボルがequal?の意味で同一になるのは,名前が同じように綴られた場合だけに限られる点で有用なオブジェクトである。これは識別子を示すのに必要十分な特徴で,多くのlisp方言ではシンボルをその目的のために内部的に使用する。シンボルはその他多くの適用例でも有用である。例えば,pascalでの列挙型の値を示すのにも用いられ得る。通常,2つのシンボルの同値性はそれらの長さに関わらず一定時間で求めることができる。 [74] symbol = identifier シンボルを書く際の規則は,識別子を書く際の規則と完全に同一とする。 8.5.4.1 シンボル型判定 (symbol? obj) この式は,objがシンボルである場合に#tを返し,そうでなければ,#fを返す。 例41: (symbol? 'foo) ==> #t (symbol? (car '(a b))) ==> #t (symbol? "bar") ==> #f (symbol? 'nil) ==> #t (symbol? '()) ==> #f (symbol? #f) ==> #f 8.5.4.2 シンボルから文字列への変換  (symbol->string symbol) この式は,symbolの名前を文字列で返す。 例42: (symbol->string 'flying-fish) ==> "flying-fish" (symbol->string (string->symbol "Malvina")) ==> "Malvina" 8.5.4.3 文字列からシンボルへの変換 (string->symbol string) この式は,引数stringをその名前とするシンボルを返す。この手続きは特殊文字を含む名前のシンボルを生成できる。しかし,特殊文字を含む名前のシンボルは外部表現形式をもたないので,そのようなシンボルの作成は通常の使用には適さない。symbol->stringを参照。 例43: (equal? 'mISSISSIppi 'mississippi) ==> #f (equal? 'bitBlt (string->symbol "bitBlt")) ==> #t (equal? 'JollyWog (string->symbol (symbol->string 'JollyWog))) ==> #t (string=? "K. Harper,M.D." (symbol->string (string->symbol "K. Harper,M.D."))) ==> #t 8.5.5 キーワード キーワードは,シンボルに類似している。主な相違点は,キーワードは自己評価的(self-evaluating)なので式内でクォートする必要がないことである。キーワードは,主にキーワード引数を指定するのに用いる。 [75] keyword = identifier : キーワードは単一のトークンで,識別子と文字:の間に空白類文字を入れてはならない。文字:は,キーワード名の一部とは見なさない。 8.5.5.1 キーワード型判定 (keyword? obj) 引数objがキーワードの場合に#tを返し,その他の場合に#fを返す。 8.5.5.2 キーワードから文字列への変換 (keyword->string keyword) 引数keywordの名前を返却する。 例44: (keyword->string Argentina:) ==> "Argentina" 8.5.5.3 文字列からキーワードへの変換 (string->keyword string) 引数stringを名前とするキーワードを返す。 例45: (string->keyword "foobar") ==> foobar: 8.5.6 名前付き定数 [76] named-constant = #!optional | #!rest | #!key 構文named-constantは,構文formal-argument-list内で用いる。名前付き定数は,自己評価的とする。名前付きオブジェクトは,他のすべてのオブジェクトの型とは異なる,それ自体の一意な(名前のない)型をもつ。 8.5.7 数量及び数値 8.5.7.1 数型 式言語は,長さと長さから派生する面積,体積などの数量を示す数量データ型を提供する。数量の表現は,SIメートルを基礎とする。SIメートルを示す単位をmとする。数量は数値と整数べき乗した単位の組合せで表現する。数量の次元は,数量を示す際にその基本単位をべき乗した数に等しい。次元が0の数量を無次元と呼ぶ。 数量を基本単位によって表現するだけでなく,他の派生単位によっても表現できると都合がよい。 [77] unit-declaration = (define-unit unit-name expression ) この宣言中の式は,数量に評価されなければならない。単位宣言は,派生数量の単位名が派生元の数量と等価であることを宣言する。この文脈では,単位名は独立したトークンとする。 派生単位として,センチメートル,ミリメートル,インチ,パイカ,ポイントは次の定義と対応し,あらかじめ定義されている。 (define-unit cm 0.01m) (define-unit mm 0.001m) (define-unit in 0.0254m) (define-unit pt 0.000352778m) (define-unit pica 0.004233333m) 数値データ型は,無次元の数量を示す数量の下位型とする。式言語は,実数及び整数の二つの数値データ型をもつ。実数は数値の下位型で,整数は実数の下位型とする。例えば,整数3は実数とも見なせるし,さらに無次元の数量とも見なせる。数量型,数値型,実数型及び整数型は,それぞれ手続きquantity?,手続きnumber?,手続きreal?及び手続きinteger?によって定義する。 角度(厳密には,平面角度)は,無次元数量つまり二つの長さの比とする。整数1は,1ラジアンと等価とする。radを無次元数量1と等しい派生単位名として宣言することを推奨する。 8.5.7.2 正確性 正確に表現されている数量と,正確ではないかもしれない数量とを区別することは必要となる。例えば,データ構造への指標は正確に分からなければならない。正確な数量が要求されている箇所での不正確な数量の使用を見つけるために,式言語は,正確な数量と不正確な数量とを明示的に区別する。この区別は,型の次元と直交する。 数量は,正確か不正確かのどちらかとなる。数量は,正確な定数として書かれた場合又は正確な数量から正確演算だけによって導かれた場合に,正確となる。数量は,不正確な定数として書かれてた場合,不正確な成分を用いて導かれた場合又は不正確な演算によって導かれた場合に,不正確となる。このように,不正確さは,数量がもつ伝搬しやすい特質である。 二つの実装が,不正確な中間結果を含まなかった計算に関して正確な結果を生成する場合,二つの最終的な結果は,数学的に等価となる。浮動小数演算などの近似法が用いられるため,不正確な数量を含む計算では,これは一般的には正しくない。しかし実装は,数学的な理想結果に,できるだけ近い結果を生成しなければならない。 手続き+などの有理数演算は,正確な変数を与えられた場合には,常に正確な結果を生成しなければならない。その演算が正確な結果を生成できなければ,実装制限の違反を報告してもよく,報告せずにその結果を強制的に不正確な値にしてもよい。 手続きinexact->exactは例外であるが,一般的に8.5.7.2に示す演算は,不正確な変数を与えられた場合には,不正確な結果を返さなければならない。しかし演算は,結果の値が変数の不正確さに影響されないことを証明できれば,正確な結果を返してよい。例えば,任意の数量と正確な0との乗算は,他の変数が不正確であっても,正確な0を出力してよい。 8.5.7.3 実装の制限 実装は,8.5.7.3の要求に従うかぎり任意の型において限定した範囲のみを保証してよい。正確値の保証範囲は,同じ型の不正確値の保証範囲と異なってよい。例えば,すべての不正確値実数を浮動小数を用いて実現した実装が,不正確実数の範囲及び不正確整数の範囲を浮動小数の表現範囲に制限しながら,実用上は制限のない正確値整数にを実現してよい。すべての実装は,-2147483647から2147483647までの範囲の正確値整数を保証しなければならない。 実装はリスト及び文字列の指標として用いる数値の範囲,並びにリスト及び文字列の長さとして返却される数値の範囲内のすべての正確値整数を保証しなければならない。手続きlength及び手続きstring-lengthは正確値整数を返却しなければならない。また,正確値整数以外を指標として用いるのは誤りである。さらに指標の範囲内にある任意の整定数は,この範囲外でどのような実装の制限が適用されるかにかかわらず,正確値整数の形式で表される限り正確値整数として解釈しなければならない。 + - * quotient remainder modulo max min abs floor ceiling truncate round expt 上述の手続きが,正確値を引数として与えられたが正確値整数を返却できない場合,実装の制限を違反したことを報告してもよいし,報告せずに結果を強制的に不正確値にしてもよい。このような変換は,後に誤りを生じるかもしれない。 実装は,不正確数を表現するのに浮動小数点及びその他の概略表現手法を用いてよい。この規格は,浮動小数表現を用いる実装はIEEEの32ビット及び64ビット浮動小数点規格を用いること及び浮動小数以外の表現形式を用いる実装は浮動小数点規格を用いることで得られる以上の精度を提供することを推奨するが,必す(須)とはしない。 特に,実装が浮動小数表現を用いる実装は,次の規則を守らなければならない。浮動小数演算の結果は,少なくともその演算に対する任意の不正確値引数の表現に用いられる精度以上の精度で表現しなければならない。手続きsqrtなどの潜在的に不正確な演算であっても,正確値の引数を適用した場合には,可能であれば正確値の結果を返すのが望ましい。例えば,正確値4の2乗根は正確値2になるのが望ましい。しかし,これも必す(須)ではない。しかし,sqrtのように正確値数量が不正確な結果をだすように演算が行なわれて結果が浮動小数点数で表される場合,最も精度の高い浮動小数形式を用いなければならない。しかし,結果が浮動小数以外の形式で表される場合,実装で利用可能な最も精度の高い浮動小数形式の精度以上の精度をもたなければならない。 実装が,正確値数量で表現できない正確値定数を読み取った場合,実装の制限を違反したことを報告してもよいし,報告せずに結果を強制的に不正確値にしてもよい。 8.5.7.4 数値定数構文  [78] number = num-2 | num-8 | num-10 | num-16 [79] num-2 = #b sign? digit-2+ [80] num-8 = #o sign? digit-8+ [81] num-16 = #x sign? digit-16+ [82] num-10 = #d ? sign? decimal exponent? unit? [83] decimal = digit-10+| . digit-10+| digit-10+ . digit-10* [84] exponent = exponent-marker sign? digit+ [85] exponent-marker = e [86] unit = unit-name (sign? digit-10+)? [87] unit-name = letter+ [88] sign = + | - [89] digit-2 = 0 | 1 [90] digit-8 = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | [91] digit-10 = digit [92] digit-16 = digit-10 | a | b | c | d | e | f [93] digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 数量は,2進数,8進数,10進数,16進数で表記でき,基数前置子で識別する。基数前置子は,#b(2進数),#o(8進数),#d(10進数),and #x(16進数)である。基数前置子なしでは,数量は10進数で表記されていると仮定する。数値定数は,小数点又は単位を含む場合に不正確値となる。それ以外は,正確値である。 備考 8.5.7.4で用いている例では,正確値記法を用いている定数は実際に正確値数量として実現されていると仮定している。いくつかの例ではまた,不正確値記法を用いている定数が正確さを失わない場合もあることを示している。不正確値定数は,不正確値数量の実現に浮動小数を用いていた実装で,不正確値となりそうなものを選んでいる。 数値定数は,単位後置子をもってよい。各単位名は,基本単位の名前であるか,単位宣言によって宣言されなければならない。単位名は構文定数expornet-markerであってはならない。単位名に数値が続かなければ,定数は,単位に関連する数量によって乗ぜられる。単位名に符号なし又は+符号付きの数値が続けば,定数は,続く数値のべきに累乗された数値名に関連する数量によって乗ぜられる。単位名に-符号付きの数値が続けば,定数は,続く数値の絶対値のべきに累乗された単位名に関連する数量によって除せられる。 8.5.7.5 数値型判定 (quantity? obj) (number? obj) (real? obj) (integer? obj) これらの手続きは,数量以外の型を含む任意の引数に対して適用できる。オブジェクトが特定の型である場合に#tを返し,そうでなければ#fを返す。一般に,ある型判定が真である場合,それより上位の型もその数量に関して真を返す。したがって,ある型判定がその数量に対して偽である場合,それより下位の型も同様にその数量に偽を返す。xが不正確値実数である場合に,(integer? x)は,(= x (round x))が成り立つ場合にだけ真となる。 例46: (real? 3) ==> #t (integer? 3.0) ==> #t 備考 上述の判定関数の不正確値に対する振る舞いは,不正確さが結果に影響するかも知れず,信頼できない。 8.5.7.6 正確性判定 (exact? q) (inexact? q) これらの手続きは,数量の正確性を判定する。任意の数量に対して,どちらか一方の判定は必ず真となる。 8.5.7.7 大小判定 (= q1 q2 q3 ...) (< q1 q2 q3 ...) (> q1 q2 q3 ...) (<= q1 q2 q3 ...) (>= q1 q2 q3 ...) その引数がそれぞれ,等しい,単調増加,単調減少,単調非減少,単調非増加である場合に,#tを返す。これらの判定は,推移的でなければならない。これらの引数の次元は,すべて同一でなければならない。 備考 不正確数量にこれらの判定を用いることは誤りではないが,不正確さが結果に影響するかも知れず信頼できない。このような現象は特に=及びzero?で顕著となる。 8.5.7.8 数値特性判定 (zero? q) (positive? q) (negative? q) (odd? n) (even? n) 数量の特性を検査し,#t又は#fを返却する。前項の注を参照のこと。 8.5.7.9 最大・最小関数 (max q1 q2 ...) (min q1 q2 ...) その引数中の最大又は最小を返却する。すべての引数の次元は,同一でなければならない。結果の次元は,引数の次元と同一となる。 例47: (max 3 4) ==> 4 ; exact (max 3.9 4) ==> 4.0 ; inexact 備考 任意の引数が不正確の場合,結果もまた不正確となる。例外として,手続きがその不正確さが結果に影響を与えるほど大きくないと判断した場合には,不正確とならない場合もある。しかし,そのような判定は,複雑な実装でだけ可能である。min又はmaxが,正確値・不正確値の混在する数量を比較するのに用いられ,結果が正確さを失わずに不正確値で示すことができない場合,手続きは実装の制限違反を報告してもよい。 8.5.7.10 加算 (+ q1 ...) 引数の合計を返却する。すべての引数は,同一の次元でなければならない。結果は,引数と同一の次元となる。 例48: (+ 3 4) ==> 7 (+ 3) ==> 3 (+) ==> 0 (* 4) ==> 4 (*) ==> 1 8.5.7.11 乗算 (* q1 ...) 引数を積を返す。結果の次元は,引数の次元の合計となる。 例49: (* 4) ==> 4 (*) ==> 1 8.5.7.12 減算 (- q1 q2) (- q) (- q1 q2 ...) 2つ以上の引数では,左から評価した引数の差を返却する。一つの場合,引数の負数を返す。すべての引数は,同一の次元でなければならない。結果の次元は,引数の次元と同一となる。 例50: (- 3 4) ==> -1 (- 3 4 5) ==> -6 (- 3) ==> -3 8.5.7.13 除算 (/ q1 q2) (/ q) (/ q1 q2 ...) 2つ以上の引数では,左から引数を評価して商を返却する。1つの場合,1を引数で割ったものを返す。結果の次元は,各引数の次元の差となる。 例51: (/ 3 4 5) ==> 3/20 (/ 3) ==> 1/3 8.5.7.14 絶対値 (abs q) 引数の絶対値を返す。 例52: (abs -7) ==> 7 8.5.7.15 整数除算 (quotient n1 n2) (remainder n1 n2) (modulo n1 n2) これらの手続きは,数論的(整数)除算を実装している。正の整数n1及びn2に関して,n3及びn4が,n1 = n2 n3 + n4 及び 0≦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は常に0又は商の符号をもつが,手続きmoduloは常に除数の符号をもつ。 例53: (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 ; 不正確 8.5.7.16 実数から整数への変換 (floor x) (ceiling x) (truncate x) (round x) これらの手続きは整数を返す。手続きfloorは,引数xより大きくない最大の整数を返す。手続きceilingは,引数xより小さくない最小の整数を返す。手続きtruncateは,引数xの絶対値より絶対値が大きくない最も近い整数を返す。手続きroundは,引数xに最も近い整数を返す。ただし,引数xが2つの整数のちょうど中間の場合には偶数に丸める。 備考 手続き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 ; inexact (round 7) ==> 7 8.5.7.17 en及び自然対数 (exp x) (log x) 手続きexpは,eの引数x乗を返す。手続きlogは,引数xの自然対数を返す。10を底とする対数ではない。 8.5.7.18 三角関数 (sin x) (cos x) (tan x) 手続きsin,手続きcos及び手続きtanはそれぞれ,引数xの正弦,余弦,正接を返す。 8.5.7.19 逆三角関数 (asin x) (acos x) (atan x) (atan q1 q2) 手続きasin,手続きacos及び手続きatanはそれぞれ,引数の逆正弦,逆余弦,逆正接を返す。2つの引数をもつ手続きatanの変形は,実数部がq2で虚数部がq1である複素数を返却する。q1及びq2の次元は等しい。手続きasinは,-π/2からπ/2の範囲の値を返す。手続きacosは,0からπの範囲の値を返す。手続きatanは,-π/2からπ/2の範囲の値を返す。 8.5.7.20 平方根関数 (sqrt q) 引数qの平方根を返す。引数qの次元は,偶数でなければならない。結果の次元は,引数qの次元の半分となる。引数qが負の場合,誤りを発生する。 8.5.7.21 指数関数 (expt x1 x2) この関数は,引数x1の引数x2乗を返す。(expt x1 0)は,1と等しいと定義する。 8.5.7.22 正確値変換 (exact->inexact q) (inexact->exact q) 手続きexact->inexactは,引数qの不正確値表現を返す。返す値は,数値的に引数に最も近い不正確数量となる。正確値が適度に近い対応する不正確値をもたない場合,実装の制限違反を報告してもよい。 手続きinexact->exactは,引数qの正確値表現を返す。返す値は,数値的に引数に最も近い正確値数量となる。不正確値が適度に近い対応する正確値をもたない場合,実装の制限違反を報告してもよい。 これらの手続きは,実装依存の範囲内で正確値と不正確値の自然な一対一対応を実現する。 8.5.7.23 数量から数値への変換 (quantity->number q) 引数qが示す数量の数値を返却する。 8.5.7.24 数値から文字列への変換 (number->string number) (number->string number radix) 引数radixは,正確値整数の2,8,10及び16のいずれかでなければならない。引数radixが省略された場合10と解釈する。手続きnumber->stringは,数値と基数を引数に取り,任意の基数をもつ任意の数値の外部表現形式の文字列として返却する。その場合次の式の評価結果が真となる。 (let ((number number) (radix radix)) (equal? number (string->number (number->string number radix) radix))) この式を評価した結果が真とならない場合は誤りとする。 引数numberが不正確値で,基数が10及び上述の式が小数点を含む結果で真であるためには,結果は小数点を含み,指数と続く0を除いて最小の数の数字を用いて表現されている必要がある。それ以外の形式では,結果は不定となる。 手続きnumber->stringが返す結果は,基数を表す前置子をもつことはない。 備考 引数numberが不正確数であって浮動小数を用いて表現されており,その基数が10の場合に,上の式は通常小数点を含む結果によって満足する。無限,NaN及び非浮動小数表現の場合には不定となる。 (format-number n string) 引数nの文字列表現を返す。引数stringには使用する形式を次のとおり指定する。 (1) 1の場合,0,1,2,... を用いる (2) 01の場合,00,01,02,... を用い,任意の先行する0について同様に振舞う。 (3) aの場合,0,a,b,c,... z,aa,ab,... を用いる。 (4) Aの場合,0,A,B,C,... Z,AA,AB,...を用いる。 (5) iの場合,0,i,ii,iii,iv,v,vi,vii,viii,ix,x,... を用いる。 (6) Iの場合,0,I,II,III,IV,V,VI,VII,VIII,IX,X,... を用いる。 (format-number-list list obj1 obj2) 引数listは整数のリストとする。引数listの文字列表現を返す。引数obj1は各数に使用する形式を指定する。それはすべての数に適用する引数format-numberと同形式の一つの文字列又はそれぞれが引数format-numberと同形式であって,引数list内の要素数と同数の文字列からなる文字列のリストとする。引数obj2は,一つの文字列又は文字列のリストであって,各数を表す文字列の分離子として用いる。それは一つの文字列又は引数listの要素数より要素数が1少ない文字列のリストとする。 8.5.7.25 文字列から数値への変換 (string->number string) (string->number string radix) 引数stringが表現する最大の正確さをもつ数値を返す。引数radixは,正確値整数で,2,8,10及び16のいずれかでなければならない。引数radixが指定された場合でも,例えば,"#o177"のようにstring中で指定した明示的な接頭辞が優先する。引数radixが省略された場合は,10と解釈する。引数stringが構文上数値として有効でない場合,手続きstring->numberは,#fを返す。 例55: (string->number "100") ==> 100 (string->number "100" 16) ==> 256 (string->number "1e2") ==> 100.0 (string->number "15##") ==> 1500.0 8.5.8 文字 文字オブジェクトは,文字を現す。 [94] character = #\ any-character | #\ character-name [95] character-name = letter (letter | digit | - | .)+ 文字は,#\文字又は#\文字名の形式を用いて表記する。例えば, (1) #\a: 小文字の'a' (2) #\A: 大文字の'A' (3) #\(: 左丸かっこ (4) #\ : 空白類文字 (5) #\space: スペースの望ましい表記 #\文字名の形式で文字がアルファベットの場合,文字名に続く文字はスペースやかっこなどの区切り文字でなければならない。この規則は,例えば文字列`#\ space'が,空白類文字の表現とも`#\ s'に`pace'が続く表現とも解釈できる曖昧さを解決する。 文字名は,文字レパートリ宣言で宣言した文字の名前でなければならない。#\記法で記述された文字は自己評価的とする。つまり,式の中でクォートする必要はない。 8.5.8.1 文字特性 この節の構文を使用するためには,機能charsetを必要とする。 すべての文字は名前付きの特性をもつ。各特性はまた無指定時値をもつ。 [96] character-property-declaration = (declare-char-property identifier expression ) この構文は識別子identifierが文字特性であって,無指定時値がexpressionの値に等しいことを宣言する。 [97] added-char-properties-declaration = (add-char-properties keyword-argument-list character+ ) [98] keyword-argument-list = (keyword expression)* 構文added-char-properties-declarationは,構文変数characterで指定した各文字に特性を追加する。構文keyword-argument-listは追加する特性を指定する。構文変数keywordは特性名を指定し,構文変数expressionは特性値を指定する。各特性は,この規格で事前に定義した特性か又は構文character-property-declarationで明示的に指定した特性のいずれかとする。 次の文字特性を事前定義とする。 (1) numeric-equiv:は,等価な数を示す整数又は#fを値とする。無指定時値は,#fとする。 追加特性は,スタイル言語で事前に定義されている。 8.5.8.2 言語依存操作 文字に関する特定の操作,例えば文字の大小変換や照合は,その文字が用いられている自然言語に依存する。言語データ型は,言語依存の操作がどのように行われるかを記述する。式はその時点で有効な言語を考慮して評価できる。有効言語が存在しない場合に,有効言語を用する手続きを呼び出すのは誤りとする。文字を操作するいくつかの手続きは文字の大小を無視する。文字の大小を無視する手続きは,-ci(大小無効の意味)がその名前に埋め込まれている。これらの手続きは,常にその引数が大文字に変換されているかのように振る舞う。これらの手続きはすべて有効言語を使用する。 (language? obj) 手続きlanguage?は,引数objが言語型の場合に#tを返し,そうでなければ#fを返す。 (current-language) 計算の任意の場所で有効言語が存在してよい。手続きcurrent-languageは,有効言語が存在すれば有効言語を,そうでなければ#fを返却する。 [99] default-language-declaration = (declare-default-language expression ) 構文default-language-declarationは,式の評価において初期値として用いられる有効言語を宣言する。式は,言語オブジェクトに評価されなければならない。 訳注 エラー訂正: 構文default-language-declarationは,中核式言語の一部ではない。 (with-language language proc) 手続きwith-languageは,引数なしの手続きを言語を有効言語として呼び出す。 8.5.8.2.1 言語定義言語定義  [100] language-definition = (define-language variable [[     collation-specification?| toupper-specification?| tolower-specification?]] ) 構文language-definitionは,変数を言語型のオブジェクトとして定義する。 訳注 エラー訂正: 構文language-definitionは,中核式言語の一部ではない。 8.5.8.2.1.1 照合  [101] collation-specification = (collate     [[multi-collating-element-specification*| collating-symbol-specification*]]      order-specification ) 構文collation-specificationは,文字列の相対順序を決定する。 備考 この照合指定の構文は,ISO 9945-2:1993に基づく。規格には読者の助けとなる例を含む。 [102] multi-collating-element-specification = (element multi-collating-element string ) [103] multi-collating-element = identifier 二つの文字列を比較する場合,各文字列は照合要素(collating-element)にまで分割される。各照合要素は単一の文字か,一つの単位として扱われる一連の文字である。構文multi-collating-element-specificationは,文字列中で単一の照合要素として扱う一連の文字を宣言する。構文order-specificationでは,この照合要素は複数照合要素識別子(multi-collating-element)によって識別できる。複数照合要素識別子として宣言された識別子は,重み識別子(weight-identifier)として用いられているものとは異なっていなければならない。 [104] collating-symbol-specification = (symbol weight-identifier ) [105] weight-identifier = identifier 構文collating-symbol-specificationは,重み識別子が構文order-specification内で用いることのできる識別子だと宣言する。 [106] order-specification = (order sort-rules collation-entry* ) [107] sort-rules = ( level-sort-rules+ ) 各構文order-specificationは,複数の異なる比較水準を定義する。二つの文字列が最初の水準で等しい場合,2番目の水準で比較が行われる。2番目の水準で等しい場合,3番目の水準で比較が行われる。この手順はすべての水準で比較を行なうか,文字列が等しくなくなるまで繰り返す。順序指定の水準の数は,構文level-sort-ruleの数で決定される。 [108] level-sort-rules = sort-keyword | (( sort-keyword+ )) [109] sort-keyword = forward | backward | position 構文level-sort-ruleは,各水準で文字列をどのように比較するかを定義する。 任意の水準で,比較する文字列中の各照合要素に0以上の重みがつけられる。結果として各文字列の順序付きリストの重みになる。"backward"及び"forward"の整列見出しは,その水準での比較方向を決定する。"backward"の整列見出しを指定した場合,比較は最後の重みを持ったものから最初の重みを持ったものへ進む。そうでなければ,最初から最後に進む。"position"の整列見出しを指定した場合,比較の際に各重みに対応する整列要素の位置を考慮する。異なる位置の二つの重みを比較する場合,比較方向で先行する場所を先に整列する。同一の整列水準規則では,"forward"及び"backward"の両者を含んではならない。 [110] collation-entry = (( collating-element level-weight* )) | weight-identifier | collating-element 各構文collation-entryは,構文order-specification内の位置で決定される重みと関連する。最初の整列項(collation-entry)が最も低い重みを持ち,2番目が次に低い重みを持ち,以降同様に続く。 整列項が重み識別子の場合,その整列項の効果は重み識別子をその整列に関連する重みを重み識別子と関連することとする。 整列要素を含む整列項は,次の二つの用途に用いる。 (1)各水準の重み整列要素に割当てる。 (2)整列要素が重み内で用いられる場合に,整列項と関連する重みを示させる。 水準重みがある水準で指定されなかった場合,整列項と関連する単一の重みが割当てられる。例えば,#\aの整列項が(#\a #\a)の整列項と同等の場合など。 [111] collating-element = character | multi-collating-element | #t 整列要素として#tを使用する場合,整列項を用いて明示的に重みが割当てられない整列要素すべてに指定した値を割当てる。 [112] level-weight = weight | weight-list [113] weight-list = ( weight* ) 水準重みは,特定の水準に割当てる重みを指定する。 [114] weight = weight-identifier | multi-collating-element | character | string 文字列の指定は,その文字列が含む文字の並びを指定するのと同じとする。 8.5.8.2.1.2 文字の大小変換 [115] toupper-specification = (toupper case-conversion-list ) [116] tolower-specification = (tolower case-conversion-list ) [117] case-conversion-list = ((character character ) )* 構文case-cnversion-listでは,構文toupper-specification又は構文tolower-specificationの文脈にしたがって,第一の文字の変換結果として,第二の文字として指定する。 8.5.8.3 文字型判定 (char? obj) 引数objが文字の場合に#tを返し,その他の場合に#fを返す。 8.5.8.4 文字比較判定 (char=? char1 char2) (char? char1 char2) (char<=? char1 char2) (char>=? char1 char2) これらの手続きは文字の集合に対して完全順序を規定する。手続きchar=?以外の手続きは有効言語を使用する。 8.5.8.5 大小無視の文字判定 (char-ci=? char1 char2) (char-ci? char1 char2) (char-ci<=? char1 char2) (char-ci>=? char1 char2) これらの手続きは,手続きchar=?などと似ているが,大文字と小文字を同じに見なす。これらすべての手続きは有効言語を使用する。例えば,(char-ci=? #\A #\a)は#tを返す。 8.5.8.6 文字の大小変換 (char-upcase char) (char-downcase char) これらの手続きが返却する,引数charに対して対応する大文字又は小文字は,有効言語で定義するものと同じとする。引数charが対応する大文字又は小文字をもたない場合,文字を返す。 8.5.8.7 文字特性 (char-property symbol char) (char-property symbol char obj) 手続きchar-propertyは,引数symbolが示す文字特性の値を返す。シンボルが文字特性でない場合,エラーが発生する。文字が引数symbolの特性をもたない場合,引数objを返す。引数objが指定されなかったときは,特性の無指定時値を返す。 8.5.9 文字列 文字列は,一連の文字である。 [118] string = " string-element* " [119] string-element = any-character-other-than-"-or-\| \" | \\ | \ character-name ; ? 文字列は,二重引用符(")で囲まれた一連の文字で表す。文字列中に表記する二重引用符は,逆スラッシュ(\)で抑制することによって次のように表記できる。 "The word \"recursion\" has many meanings." 逆スラッシュは,文字列中で他の逆スラッシュによって抑制することによって表記できる。文字列中の任意の文字は,逆スラッシュに続けてその名前を表記することによって示すことができる。名前はその文字列中で続く文字がないか又は続く文字が構文定数subsequentでない場合以外は,セミコロンで区切らなければならない。個々で用いる名前は,文字の#\構文で用いるものと同じとする。 文字列定数は1つのレコードから次のレコードに続いてよく,その場合実体中に二つのレコードを分割する文字を含むこととなる。 文字列の長さは,その文字列が含む文字の数である。この数は文字列が生成されたときに確定する非負整数である。文字列の有効な指標は,非負の正確値整数で,文字列の長さ未満のものである。文字列の最初の文字は指標0で,2番目は1で,以降同様の指標で参照する。 指標startで始まり,指標endで終わる文字列の文字などの句では,指標startは含まれ,指標endは含まれないとする。したがって,start及びendが同じ指標を示す場合,長さ0の部分文字列が参照されている。startが0でendが文字列の長さの場合,文字列全体が参照されている。 文字列を操作するいくつかの手続きは,操作前に文字列を大文字に変換することによって文字の大小の違いを無視する。文字の大小を無視する場合の手続きは,その名前に-ci(大小を区別しないの意味)を埋め込まれている。 8.5.9.1 文字列型判定 (string? obj) 引数objが文字列の場合#tを返し,その他の場合に#fを返す。 8.5.9.2 文字列生成 (string char ...) 一連の引数からなる文字列を返す。 8.5.9.3 文字列長 (string-length string) 引数stringの文字数を返す。 8.5.9.4 文字列アクセス (string-ref string k) 引数kは,引数stringの有効な指標でなければならない。手続きstring-refは,0を起点とする引数kを指標として用い,引数string中の文字を返す。 8.5.9.5 文字列等価性 (string=? string1 string2) (string-ci=? string1 string2) 二つの文字列が同じ長さで,同じ文字を同じ位置にもつ場合に#tを返し,その他の場合に#fを返す。手続きstring-ci=?は,文字の大小を無視するが,手続きstring=?は文字の大小を区別する。手続きstring-ci=?は,有効言語を使用する。 (string-equiv? string1 string2 k) 二つの文字列が,有効言語の照合指定において,最初から引数kが示す数の比較水準において同一の場合に#tを返し,その他の場合に#fを返す。ここで引数kは正でなければならない。 8.5.9.6 文字列比較 (string? =? string1 string2) (string-ci? string1 string2) (string-ci<=? string1 string2) (string-ci>=? string1 string2) これらの手続きは,文字の順序付けに対応する辞書順の文字列への拡張である。例えば,手続きstringlist string) (list->string chars) 手続きstring->listは,文字列を構成する文字からなるリストを返却する。手続きlist->stringは,引数charsが示す文字のリスト中の文字から成る文字列を返却する。手続きstring->list及び手続きlist->stringは,equal?の観点からは逆変換となる。 8.5.10 手続き 8.5.10.1 手続き型判定 (procedure? obj) 引数objが手続きの場合に#tを,その他の場合に#fを返す。 例56: (procedure? car) ==> #t (procedure? 'car) ==> #f (procedure? (lambda (x) (* x x))) ==> #t (procedure? '(lambda (x) (* x x))) ==> #f 8.5.10.2 手続き適用 (apply proc args) (apply proc arg1 ... args) 引数procは手続きであって,引数argsはリストでなければならない。最初の(基本の)形式は,実際の引数として引数argsの要素をもつ手続きprocを呼び出す。2番目の形式は,最初のものを一般化したもので,リスト(append (list arg1 …) args)の要素を実際の引数として引数procを呼び出す。 例57: (apply + (list 3 4)) ==> 7 (define compose (lambda (f g) (lambda args (f (apply g args))))) ((compose sqrt *) 12 75) ==> 30 8.5.10.3 リスト間対応手続き (map proc list1 list2 ...) 引数listはリスト,引数procはlistと同じ数の引数を取る手続きでなければならない。一つ以上の引数listが与えられた場合,それらはすべて同じ長さでなければならない。手続きmapは,引数procを引数listの要素一つずつに適用し,右から左に連結した結果のリストを返す。 例57: (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) 8.5.10.4 外部手続き (external-procedure string) 手続きexternal-procedureは,引数stringを公開識別子とする外部手続きの手続きオブジェクトを返す。処理系が外部手続きを見いだせない場合,#fを返却する。手続きオブジェクトに渡された引数は,外部手続きに引き渡される。引数の数又は型が,外部手続きの期待するものと異なる場合には,エラーを発生してよい。手続きオブジェクトを呼び出すことで外部手続きの実行結果が得られる。外部手続きは,副作用無しの方が望ましい。実装はそのように仮定してよい。それらの手続きは,処理系から情報を得るためにもちいるべきで,処理系の状態を変えるべきではない。 8.5.11 日付及び時間 (time) (time->string k) (time->string k boolean) 手続きtimeは,1970年1月1日午前0時0分秒(GMT)から経過した秒数を整数として返す。手続きtime->stringは,手続きtimeが返す日付及び時間の整数表現をISO 8601の形式の文字列に変換する。引数booleanが存在し,それが真の場合,文字列表現はGMTに基づくものとなり,その他の場合に地方時間を示す。 8.5.12 誤り発生 (error string) 手続きerrorは,エラーを発生する。引数stringはエラーを説明する。エラーが発生した場合の処理系の挙動は,処理系定義とする。特に,エラーを利用者に報告する様式は処理系定義とする。しかし,引数stringはエラー報告に使用し,エラーが発生した文脈を説明するのが望ましい。手続きerrorは,値を返さない。 8.6 中核式言語 中核式言語と呼ぶ,式言語の部分集合を8.6において規定する。中核式言語においては,8.6の規則に従う式及び定義だけが利用でき,8.6の原型をもつ手続きだけが利用可能となる。中核式言語において有効であるすべての式又は定義は,完全仕様式言語におけるその意味と同じ意味をもつ。 8.6.1 構文 [120] expression = primitive-expression | derived-expression [121] primitive-expression = variable-reference | literal | procedure-call | conditional [122] variable-reference = variable [123] variable = identifier [124] literal = quotation | self-evaluating [125] quotation = 'datum | (quote datum ) [126] datum = simple-datum | list [127] simple-datum = boolean | number | character | string | symbol | keyword | glyph-identifier [128] list = (datum* ) | 'datum [129] self-evaluating = boolean | number | character | string | keyword | glyph-identifier [130] procedure-call = (operator operand* ) [131] operator = expression [132] operand = expression [133] conditional = (if test consequent alternate ) [134] test = expression [135] consequent = expression [136] alternate = expression [137] derived-expression = cond-expression | case-expression | and-expression | or-expression [138] cond-expression = (cond cond-clause+ ) | (cond cond-clause* (else expression ) ) [139] cond-clause = (test expression ) [140] case-expression = (case keycase-clause+ ) | (case keycase-clause* (else expression ) ) [141] key = expression [142] case-clause = (( datum* ) expression ) [143] and-expression = (and test*) [144] or-expression = (or test* ) [145] definition = (define variable expression ) 8.6.2 手続き (not obj) (boolean? obj) (equal? obj1 obj2) (null? obj) (list? obj) (list obj ...) (length list) (append list ...) (reverse list) (list-tail list k) (list-ref list k) (member obj list) (symbol? obj) (keyword? obj) (quantity? obj) (number? obj) (real? obj) (integer? obj) (= q1 q2 q3 ...) (< q1 q2 q3 ...) (> q1 q2 q3 ...) (<= q1 q2 q3 ...) (>= q1 q2 q3 ...) (max q1 q2 ...) (min q1 q2 ...) (+ q1 ...) (* q1 ...) (- q1 q2) (- q) (/ q1 q2) (/ q) (abs q) (quotient n1 n2) (remainder n1 n2) (modulo n1 n2) (floor x) (ceiling x) (truncate x) (round x) (sqrt q) (number->string number) (number->string number radix) (string->number string) (string->number string radix) (format-number n string) (format-number-list list obj1 obj2) (char? obj) (char=? char1 char2) (char-property symbol char) (char-property symbol char obj) (string? obj) (string char ...) (string-length string) (string-ref string k) (string=? string1 string2) (substring string start end) (string-append string ...) (procedure? obj) (apply proc args) (external-procedure string) (time) (time->string k) (time->string k boolean) (error string)