条件式

すべての言語と同様に、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)として 定義することができます。

4.1  whenunless

whenunlessはひとつの枝(“then”あるいは“else”の枝)しかない 基本条件式が必要なときに便利です。

(when (< (pressure tube) 60)
   (open-valve tube)
   (attach floor-pump tube)
   (depress floor-pump 5)
   (detach floor-pump tube)
   (close-valve tube))

tubepressure60未満と仮定すると、この条件式は floor-pumptubeに取り付け、5回押します (attachdepressはなにか適当な手続きです)。

同じプログラムを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がwhenunlessを用意しているわけではありません。 おつかいのSchemeになければ、マクロ(8章参照)として定義できます。

4.2  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です。

4.3  case

condの特別な場合にはcase式で圧縮した表現にできます。 これはすべてのテストが所属テストの場合です。

(case c
  ((#\a) 1)
  ((#\b) 2)
  ((#\c) 3)
  (else 4))
=>  3

cの値を先頭にもつ節が選択されます。

4.4  andor

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

andorはともにサブフォームを左から右へ評価します。 結果が決りしだい返すことができるのでandorはのこりの サブフォームを無視することがあります。

(and 1 #f expression-guaranteed-to-cause-error)
=>  #f

(or 1 #f expression-guaranteed-to-cause-error)
=>  1