Scheme 提供了三种主要的条件语句:if、cond 和 case。它们用于根据表达式的真假值选择不同的执行路径。理解这三者的区别和适用场景,能让你写出更清晰、更符合 Scheme 风格的代码。
使用 if 处理二选一逻辑
if 是最简单的条件结构,适用于只有“真”和“假”两种结果的情况。
语法格式:
(if <条件表达式> <为真时执行的表达式> <为假时执行的表达式>)
注意:if 必须提供三个部分——条件、真分支、假分支。不能省略假分支。
-
编写一个判断正数的函数:
(define (positive-or-not x) (if (> x 0) "positive" "not positive"))- 当
x大于 0 时,返回"positive"。 - 否则返回
"not positive"。
- 当
-
嵌套
if实现多分支(不推荐):(define (sign x) (if (> x 0) 1 (if (< x 0) -1 0)))- 虽然可行,但嵌套会使代码难以阅读。此时应改用
cond。
- 虽然可行,但嵌套会使代码难以阅读。此时应改用
使用 cond 处理多分支选择
cond 是处理多个条件分支的首选方式,结构清晰,可读性强。
语法格式:
(cond
(<条件1> <结果1>)
(<条件2> <结果2>)
...
(else <默认结果>))
每个子句是一个括号包裹的列表,包含一个条件和一个或多个表达式。一旦某个条件为真,就执行其对应的结果表达式,并返回最后一个表达式的值。else 子句作为兜底选项,必须放在最后。
-
重写
sign函数使用cond:(define (sign x) (cond ((> x 0) 1) ((< x 0) -1) (else 0))) -
在
cond子句中执行多个表达式:(define (check-grade score) (cond ((>= score 90) (display "Excellent!\n") 'A) ((>= score 80) (display "Good job.\n") 'B) (else 'F)))- 每个分支可以包含多个表达式,按顺序执行,返回最后一个表达式的值。
-
避免遗漏
else导致未定义行为:- 如果所有条件都不满足且没有
else,cond返回未指定值(通常显示为#<void>或类似)。务必添加else分支以确保程序健壮。
- 如果所有条件都不满足且没有
使用 case 基于精确值进行分发
case 适用于根据某个表达式的具体值(通常是符号、数字或字符串)选择分支。它内部使用 equal? 进行比较。
语法格式:
(case <表达式>
((值1 值2 ...) <结果1>)
((值3 值4 ...) <结果2>)
...
(else <默认结果>))
<表达式>先被求值,然后与每个子句中的值列表进行匹配。- 匹配成功时,执行对应的结果表达式。
else同样作为默认分支,必须放在最后。
-
根据星期几返回工作状态:
(define (work-day? day) (case day ((mon tue wed thu fri) #t) ((sat sun) #f) (else (error "Invalid day"))))- 输入
mon、tue等符号时返回#t(是工作日)。 - 输入
sat或sun返回#f。 - 其他输入抛出错误。
- 输入
-
匹配数字范围(注意:
case不支持范围,仅支持离散值):(define (digit-name d) (case d ((0) "zero") ((1) "one") ((2) "two") (else "unknown digit")))- 不能写成
((0 1 2))表示范围,这里(0 1 2)表示匹配 0、1 或 2 中任意一个值。 - 若需范围判断(如 0–9),应使用
cond配合<=和>=。
- 不能写成
-
case的限制:- 只能匹配字面量(literals),不能使用变量或表达式作为匹配项。
- 例如,以下写法是错误的:
(define x 5) (case 5 ((x) "matched")) ; 错误!这里匹配的是符号 'x',不是变量 x 的值
三者对比与选择建议
| 结构 | 适用场景 | 条件类型 | 默认分支 | 多表达式支持 |
|---|---|---|---|---|
if |
二选一 | 任意布尔表达式 | 必须显式提供 | 否(单表达式) |
cond |
多条件分支 | 任意布尔表达式 | 可选(推荐加 else) |
是 |
case |
精确值分发 | 字面量列表(用 equal? 比较) |
可选(推荐加 else) |
是 |
选择原则:
- 只有两个结果? → 使用
if。 - 需要判断多个不相关的条件(如
x > 0、y < 10、(null? lst))? → 使用cond。 - 根据一个表达式的具体值(如
'start、'stop、42)做选择? → 使用case。
避免常见错误:
- 不要用
case判断范围或复杂条件。例如,判断成绩等级应使用cond,而非试图在case中列出所有分数。 - 不要在
if中省略 else 分支,除非你明确知道后果(比如只关心副作用且 false 时无需操作)。 - 不要在
cond或case中遗漏else,除非你能保证所有可能情况都被覆盖。
实战示例:统一处理用户输入
假设你要解析用户输入的命令,可能是 'start、'stop、'restart 或无效命令。
(define (handle-command cmd)
(case cmd
((start)
(display "Starting service...\n")
'started)
((stop)
(display "Stopping service...\n")
'stopped)
((restart)
(handle-command 'stop)
(handle-command 'start)
'restarted)
(else
(display "Unknown command: ")
(write cmd)
(newline)
'error)))
- 使用
case因为命令是离散的符号。 restart分支调用了两次handle-command,展示了case支持多表达式。else分支处理非法输入,保证程序不会静默失败。
记住:if 用于简单二分,cond 用于通用多条件,case 用于值匹配。根据问题本质选择最合适的结构,代码自然简洁可靠。

暂无评论,快来抢沙发吧!