第四章,条件语句

和其它的编程语句一样,Scheme 也包含条件语句。

最基本的结构就是if:

  1. (if 测试条件
  2. then-分支
  3. else-分支)

如果测试条件运算的结果是真(即,非#f的任何其它值),then分支将会被运行(即满足条件时的运行分支)。否则,else分支会被运行。else分支是可选的。

  1. (define p 80)
  2. (if (> p 70)
  3. 'safe
  4. 'unsafe)
  5. => safe
  6. (if (< p 90)
  7. 'low-pressure) ;no ``else'' branch
  8. => low-pressure

为了方便,Scheme还提供了一些其它的条件结构语句。它们可以被定义成宏来扩充if表达式。

4.1 when 和 unless

当我们只需要一个基本条件语句分支时(”then”分支或”else”分支),使用when 和 unless会更方便。(这里的示例已经更换,原示例)

  1. (define a 10)
  2. (define b 20)
  3. (when (< a b)
  4. (display a是”)
  5. (display a)
  6. (display b是”)
  7. (display b)
  8. (display a大于b ) )

先判断a是否小于b,这个条件成立时会输出5条信息。

使用if实现相同的程序会是这样:

  1. (define a 10)
  2. (define b 20)
  3. (if (< a b)
  4. (begin
  5. (display a是”)
  6. (display a)
  7. (display b是”)
  8. (display b)
  9. (display a大于b ) ))

注意when的分支是一个隐式的begin语句结构,
而如果if的分支有多个代码结构时,需要一个显式的begin代码结构。

同样的功能还可以像下面这样用unless来写(unlesswhen的意思正好相反):

  1. (define a 10)
  2. (define b 20)
  3. (unless (>= a b)
  4. (display a是”)
  5. (display a)
  6. (display b是”)
  7. (display b)
  8. (display a大于b ) )

并不是所有的Scheme环境都提供whenunless
如果你的Scheme中没有,你可以用宏来自定义出whenunless(宏,见第8章)。

4.2 cond

cond结构在表示多重if表达式时很方便,
多重if结构除了最后一个else分支以外的其余分支都会包含一个新的if条件。因此,

  1. (if (char<? c #\c) -1
  2. (if (char=? c #\c) 0
  3. 1))

这样的结构都可以使用cond来这样写:

  1. (cond ((char<? c #\c) -1)
  2. ((char=? c #\c) 0)
  3. (else 1))

cond就是这样的一种多分支条件结构。每个从句都包含一个判断条件和一个相关的操作。第一个判断成立的从句将会引发它相关的操作执行。如果任何一个分支的条件判断都不成立则最后一个else分支将会执行(else分支语句是可选的)。

cond的分支操作都是begin结构。

4.3 case

cond结构的每个测试条件是一个测试条件的分支条件时,可以缩减为一个case表达式。

  1. (define c #\c)
  2. (case c
  3. ((#\a) 1)
  4. ((#\b) 2)
  5. ((#\c) 3)
  6. (else 4))
  7. => 3

分支头值是#\c 的分支将被执行。

4.4 and 和 or

Scheme提供了对boolean值进行逻辑与and和逻辑或or运算的结构。(我们已经见过了布尔类型的求反运算not过程。)

当所有子结构的值都是真时,and的返回值是真,实际上,and的运行结果是最后一个子结构的值。如果任何一个子结构的值都是假,则返回#f

  1. (and 1 2) => 2
  2. (and #f 1) => #f

or会返回它第一个为值为真的子结构的结果。如果所有的子结构的值都为假,or则返回#f

  1. (or 1 2) => 1
  2. (or #f 1) => 1

andor都是从左向右运算。当某个子结构可以决定最终结果时,andor会忽略剩余的子结构,即它们是“短路”的。

  1. (and 1 #f expression-guaranteed-to-cause-error)
  2. => #f
  3. (or 1 #f expression-guaranteed-to-cause-error)
  4. => 1