より一般化された cond
節
Taylor Campbell
この SRFI は現在「確定」の状態である。 SRFI の各状態の説明については ここ を参照せよ。 この SRFI に関する議論については メーリングリストのアーカイブ を参照せよ。
この SRFI では cond
構文の拡張を提案する。
この拡張では、
より一般化された節を使うことができ、
=>
節のようなテスト結果を束縛することができ、
テストの成功と失敗の意味をユーザー定義可能にする。
現状の cond
節は、単純なブール値のテストをベースにしている。
この制限は表現力が弱く、
=>
を使用する
cond
節の条件部は
1つの値しか渡すことができないので、
#f
が条件の失敗を表すという意味論にならざるを得ない。
プログラマは失敗を表すのに異なる表現を使うことがよくある。
R5RS の I/O リーダーは失敗を表すのに「EOF オブジェクト」を返すし、
成功した場合は複数の値を返すかも知れない。
ここで提案する簡単な拡張を使うと、
節ごとに「失敗」の意味を割り当てることができ、
条件が多重値を返すことができる。
R5RS の section 7.1.3 に示されている Scheme の形式構文における
<cond clause>
の生成規則を、新しいオプションを追加する形で拡張する。
<cond clause> ---> ... | (<generator> <guard> => <receiver>)
ここで <generator>
, <guard>
, <receiver>
はすべて <expression>
である。
この形式の節は次のような意味論を持つ:
<generator>
が評価される。
これは任意の個数の値を返すことができる。
<generator>
の戻り値を引数リストとして
<guard>
を適用する。
その引数リストに対して <guard>
が真を返すなら、
その同じ引数リストに対して <receiver>
を適用する。
<guard>
が偽を返すなら、
その節は無視され、次の節が試行される。
次に示す port->char-list
手続きは、
入力ポートを受け取り、その入力ポートの終端までの全ての文字のリストを返す。
(define (port->char-list port) (cond ((read-char port) char? => (lambda (c) (cons c (port->char-list port)))) (else '())))
テーブル (おそらくはハッシュ テーブル) とそのエントリのキーという
2つの引数を受け取る table-entry
という手続きを考えてみよう。
この手続きは、キーがテーブルに存在するかを表すブール値と、
もしキーが存在するなら、そのキーに関連付けられた値、という2つの値を返すとしよう。
また、proj0
(引数 0 の射影) というコンビネータがあって、
これは、引数リストのうちの最初の引数のみを返し、
それ以外の引数を無視するとしよう。
このような場合、テーブルがキーを持ならば特定のコードを実行する条件分岐を、
新しい cond
節を用いて、次のようにして実装することができる。
(cond ... ((table-entry <table> <key>) proj0 => (lambda (present? value) ...[VALUE にはエントリの値が束縛される]...)) ...)
この新しい cond
の構文トランスフォーマを以下に示す。
この実装では cond/maybe-more
という補助マクロを使用している。
このマクロを使うと cond
節を持つ (または持たない) if
式を簡単に作成できる。
下記のコードはパブリック ドメインとする。
(define-syntax cond (syntax-rules (=> ELSE) ((COND (ELSE else1 else2 ...)) ;; The (IF #T (BEGIN ...)) wrapper ensures that there may be no ;; internal definitions in the body of the clause. R5RS mandates ;; this in text (by referring to each subform of the clauses as ;; <expression>) but not in its reference implementation of COND, ;; which just expands to (BEGIN ...) with no (IF #T ...) wrapper. (IF #T (BEGIN else1 else2 ...))) ((COND (test => receiver) more-clause ...) (LET ((T test)) (COND/MAYBE-MORE T (receiver T) more-clause ...))) ((COND (generator guard => receiver) more-clause ...) (CALL-WITH-VALUES (LAMBDA () generator) (LAMBDA T (COND/MAYBE-MORE (APPLY guard T) (APPLY receiver T) more-clause ...)))) ((COND (test) more-clause ...) (LET ((T test)) (COND/MAYBE-MORE T T more-clause ...))) ((COND (test body1 body2 ...) more-clause ...) (COND/MAYBE-MORE test (BEGIN body1 body2 ...) more-clause ...)))) (define-syntax cond/maybe-more (syntax-rules () ((COND/MAYBE-MORE test consequent) (IF test consequent)) ((COND/MAYBE-MORE test consequent clause ...) (IF test consequent (COND clause ...)))))
Copyright (C) 2004 Taylor Campbell. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.