[R7RS base]
まずtest
を評価し、それが真の値を返したらconsequentを評価します。
そうでなければalternativeを評価します。もしalternativeが与えられて
いなければ未定義の値を返します。
(if (number? 3) 'yes 'no) ⇒ yes
(if (number? #f) 'yes 'no) ⇒ no
(let ((x '(1 . 2)))
(if (pair? x)
(values (car x) (cdr x))
(values #f #f)))
⇒ 1 and 2
[R7RS+ base][SRFI-61] 各clause節は次のいずれかの形式でなければなりません。
(test expr ...) (test => expr) (test guard => expr) (else expr expr2 ...)
最後の形式は最後の節のみに許されます。
最初の節から順にtestが評価され、それが真の値を返すまで次の節のtestが
評価されます。testが真の値を返したら、それが最初の形式であれば
その節のexprが順に評価され、最後の評価値が戻り値となります。
それが2番目の形式であれば、exprがまず評価されます。
exprは引数をひとつ取る手続きを返さねばなりません。
続いて、testの結果がその手続きに渡され、その手続きの戻り値がcond
形式の
評価値となります。
3番目の形式はSRFI-61で定義されています。この形式では、testは
任意の数の値に評価されることができます。それらの値がまず
guardに渡され、もしguardが真の値を返したら、同じ引数がexprに
適用されて、その戻り値がcond
形式の評価値となります。
guardが#f
を返した場合は次の節へと評価が進みます。
guardとexpr
は、testが返すのと同数の引数を取れなければいけません。
もし全てのテストが偽の値を返し、最後の節が4番目の形式(else節)でなければ、未定義の値が返されます。
最後の節がelse
節で、他の全てのテストが失敗した場合、else
節のexpr
が順に評価され、その最後の値がcond
形式の値となります。
(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
[R7RS+ base][SRFI-87] key-exprは1つの値を生成する任意の式です。 clauseは以下の形式でなければなりません。
((datum ...) expr expr2 ...) ((datum ...) => proc)
ここで、各datumはSchemeオブジェクトの外部表現であり、全てのdatumは 異なっていなければなりません。最後のclauseには次の形式を持つelse節が許されます。
(else expr expr2 ...) (else => proc)
まずkey-exprが評価され、その結果がそれぞれのdatumと比較されます。
key-exprの値とeqv?
(等価参照)を使って一致するdatum
が見つかれば、対応するexprが順に評価され、その最後の値がcase
の
値となります。=>
を含む節はSRFI-87で定義されています。これらの節では、
key-exprの結果がprocに渡され、その結果がcase
の値となります。
もし一致するdatumが見つからない場合、else節が与えられていれば
そのexprが順に評価され、最後の値が返されます。else節がなければcase
節
の値は未定義です。
(case (* 2 3)
((2 3 5 7) 'prime)
((1 4 6 8 9) 'composite)) ⇒ composite
(case (car '(c d))
((a) 'a)
((b) 'b)) ⇒ undefined
(case (car '(c d))
((a e i o u) 'vowel)
((w y) 'semivowel)
(else 'consonant)) ⇒ consonant
(case 6
((2 4 6 8) => (cut + <> 1))
(else => (cut - <> 1))) ⇒ 7
(case 5
((2 4 6 8) => (cut + <> 1))
(else => (cut - <> 1))) ⇒ 4
このフォームはほぼcase
と同等ですが、else
節が与えられず、
key-exprの値がclause中のどのdatumとも一致しなかった場合の
動作だけが異なります。case
ではそのような場合は未定義値が返されますが、
ecase
はエラーを報告します。
このマクロはCommon Lispから採られました。想定外の値が渡されることを 念のために検出したい、という場合に便利です。
(ecase 5 ((1) 'a) ((2 3) 'b) ((4) 'c)) ⇒ ERROR: ecase test fell through: got 5, expecting one of (1 2 3 4)
これはCommon Lispから採られました。
key-exprはひとつの値を生成するScheme式です。
各clauseは次のいずれかの形式でなければなりません。
else
節は、現れるなら最後のclauseでなければなりません。
(type-expr expr ...) (else expr1 expr2 ...)
各type-exprは型の式でなければなりません (型とクラス参照)。
このマクロはまずkey-exprを評価し、次にその値が型type-exprであるかどうかを
順番に検査してゆきます。もし型の制約が満たされたら、その節にあるexpr …
が評価され、その最後の値がtypecase
の値となります。
型の制約はof-type?
で検査されます (汎用型述語参照)。
どの節の型でもなかった場合、else
節があればその中の式が順に評価されて最後の値が
typecase
の値となり、else
節がなければ未定義値が返されます。
(typecase key-expr (<integer> 'a) ((</> <string> <symbol>) 'b)) ≡ (let ((tmp key-expr)) (cond ((of-type? tmp <integer>) 'a) ((of-type? tmp (</> <string> <symbol>)) 'b)))
typecase
と似ていますが、key-exprの結果が
どのtype-exprの型でもなく、またelse
節がなかった場合、
エラーが投げられます。else
節がある場合は
typecase
と同じです。
(etypecase (sqrt -2) (<integer> 'int) (<real> 'real)) ⇒ *** ERROR: etypecase fell through: expecting one of types in (<integer> <real>), but got 0.0+1.4142135623730951i
[R7RS base]
test式が順に評価されます。最初に偽の値を返したところで評価が止まり、
偽の値が返されます。残りの式は評価されません。
もし全ての式が真の値を返した場合は、最後の式の値が返されます。
式が与えれない場合は#t
が返されます。
(and (= 2 2) (> 2 1)) ⇒ #t (and (= 2 2) (< 2 1)) ⇒ #f (and 1 2 'c '(f g)) ⇒ (f g) (and) ⇒ #t
[R7RS base]
test式が順に評価されます。最初に真の値を返したところで評価が止まり、
その値が返されます。残りの式は評価されません。
もし全ての式が偽の値を返した場合は、偽の値が返されます。
式が与えれない場合は#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)
[R7RS base]
まずtestが評価されます。それが真の値(unless
の場合は偽の値)を返した場合、
引続きexpr1およびexpr2 …が順に評価され、最後の評価値が返されます。
そうでなければ、未定義の値が返されます。
[SRFI-145] test-exprを評価してその値を返します。
また、このフォームに続くコードパスにおいて、test-exprが常に満たされている、 というプログラマの意図を宣言します。
Gaucheでは今のところ、text-exprが偽となった場合は常にエラーが投げられます。
(define (rsqrt x) (assume (and (real? x) (>= x 0))) (sqrt x)) gosh> (rsqrt -1) *** ERROR: Invalid assumption: (and (real? x) (>= x 0))
省略可能な引数 message obj … が与えられた場合、
それらはtest-exprが偽を返した際にerror
の引数に使われます。
(define (rsqrt x) (assume (and (real? x) (>= x 0)) "Argument must be nonnegative real number, but got:" x) (sqrt x)) gosh> (rsqrt -1) *** ERROR: Argument must be nonnegative real number, but got: -1
註: このフォームは勧告として機能します。
test-exprが失敗してもエラーが投げられるとは限りません。例えば、
将来、最適化オプションをつけて、
速度最適化レベルが高い時はテストを省略するようになるかもしれません。
また一方で、この情報を利用してコンパイラがより良いコードを出すように拡張される
可能性もあります。例えば上のreal-sqrt
の例では、コンパイラは理論的には
(sqrt x)
が実関数として動作すれば良いということを演繹できるため、
実数に特化したコードを生成できる可能性があります。
このフォームを、コードの書き手の意図をコンパイラやコードの読み手に知らせるために
用いると良いでしょう。
exprを評価し、その値が型typeかどうかチェックします。 型が合わなければエラーを投げます。exprの値が返されます。
typeにはGaucheのクラスか記述的な型を指定できます。
値がその型かどうかは(of-type? value type)
で判定されます
(型とクラス参照)。
省略可能な引数 message obj … が与えられた場合、
それらはtest-exprが偽を返した際にerror
の引数に使われます。
(define (strlen s) (assume-type s <string>) (string-length s)) gosh> (strlen 4) *** ERROR: s is supposed to be of type #<class <string>>, but got 4 (define (strlen s) (assume-type s <string> "Argument s must be a string, but got:" s) (string-length s)) gosh> (strlen 4) *** ERROR: Argument s must be a string, but got: 4
このフォームによる情報は、将来のコンパイラで最適化に使われるかもしれません。 コンパイラが型制約の情報を利用するためには、typeが静的に型へと計算可能でなければ なりません。すなわち、クラスか、型コンストラクタか、それらへのconstantな束縛です。
註: assume
と同様、このフォームも勧告として機能します。
チェックがなされるか、exprが評価されるかどうかは保証されません。