すべての言語と同様に、Schemeには条件式があります。
基本フォームはifです。
(if test-expression then-branch else-branch)
test-expressionが評価されて真(すなわち、#f以外の値)になれば、
“then”の枝が評価されます。さもなければ、“else”の枝が評価されます。
“else”の枝はなくてもかまいません。
(define p 80) (if (> p 70) 'safe 'unsafe) => safe (if (< p 90) 'low-pressure) ;no ``else'' branch => low-pressure
Schemeでは利便のために他にも条件式フォームが用意されています。
これらはすべて、if式に展開されるマクロ(chap 8)として
定義することができます。
whenとunless
whenとunlessはひとつの枝(“then”あるいは“else”の枝)しかない
基本条件式が必要なときに便利です。
(when (< (pressure tube) 60) (open-valve tube) (attach floor-pump tube) (depress floor-pump 5) (detach floor-pump tube) (close-valve tube))
tubeのpressureが60未満と仮定すると、この条件式は
floor-pumpをtubeに取り付け、5回押します
(attachとdepressはなにか適当な手続きです)。
同じプログラムをifを使うと次のようになります。
(if (< (pressure tube) 60) (begin (open-valve tube) (attach floor-pump tube) (depress floor-pump 5) (detach floor-pump tube) (close-valve tube)))
whenの枝は暗黙のbeginであり、一方、ifでは
どちらかのブランチに2つ以上フォームがあるときには
明示的なbeginが必要です。
同じ振舞いをunlessをつかって書けば以下のようになります。
(unless (>= (pressure tube) 60) (open-valve tube) (attach floor-pump tube) (depress floor-pump 5) (detach floor-pump tube) (close-valve tube))
すべてのSchemeがwhenとunlessを用意しているわけではありません。
おつかいのSchemeになければ、マクロ(8章参照)として定義できます。
cond
condフォームは入れ子になったif式を表現するのに便利です。
最後以外の“else”の枝には新しいifが導入されます。したがって、
(if (char<? c #\c) -1 (if (char=? c #\c) 0 1))
はcondをつかって、次のように書けます。
(cond ((char<? c #\c) -1) ((char=? c #\c) 0) (else 1))
このように、condはマルチブランチの条件式です。
各節にはテストとそれに結びつくアクションがあります。
最初に成功したテストがそれに結びついたアクションを起します。
最後のelse節はどのテストも成功しなかった場合に選択されます。
condのアクションは暗黙のbeginです。
case
condの特別な場合にはcase式で圧縮した表現にできます。
これはすべてのテストが所属テストの場合です。
(case c ((#\a) 1) ((#\b) 2) ((#\c) 3) (else 4)) => 3
cの値を先頭にもつ節が選択されます。
andとor
Schemeには論理積(“and”)と論理和(“or”)に対応するスペシャルフォームが
用意されています(2.1.1節で見た否定のnotは手続きです)。
スペシャルフォームandはすべてのサブフォームが真ならば真を返します。
実際に返ってくる値は最後のサブフォームの値です。サブフォームのひとつでも
偽であれば、andは#fを返します。
(and 1 2) => 2 (and #f 1) => #f
スペシャルフォームorは最初に真になったサブフォームの値を返します。
もし、すべてのサブフォームが偽ならばorは#fを返します。
(or 1 2) => 1 (or #f 1) => 1
and、orはともにサブフォームを左から右へ評価します。
結果が決りしだい返すことができるのでandとorはのこりの
サブフォームを無視することがあります。
(and 1 #f expression-guaranteed-to-cause-error) => #f (or 1 #f expression-guaranteed-to-cause-error) => 1