在像 Scheme 这样的非纯函数式语言中,允许在语法中有空间的地方使用一系列表达式通常很有用:例如在过程的主体中等等。因此,例如,一个纯函数式 Lisp 可能有一个函数语法,它是
(λ (<arg> ...)
<expression>)
但是 Scheme 允许
(λ (<arg> ...)
<expression-1>
<expression-2>
...)
除了最后一个表达式之外的所有值都被忽略:它们只是因为副作用而发生。由于在语法中有空间,Scheme 允许这样做。
然而,在 if 的语法中根本没有空间用于这种情况(见下文)。
有可能设计多路条件表达式还它的语法没有空间,它可能看起来像:
(kond
a 1
b 2
c 3
else 4)
例如(这里 else 对 kond 来说很神奇:我不记得 SICP 的方案是否有)。
但是如果你考虑一下cond 的语法实际上是什么:
(cond
(a 1)
(b 2)
(c 3)
(else 4))
然后那里是显然,现在语法中有空间在每个子句的结果位置写入一系列表达式。因此,Scheme 确实允许这样做,因为根本没有理由不这样做。所以而不是
(cond
(<t> <e>)
...)
你可以写
(cond
(<t> <e1> <e2> ...)
...)
例如:
(cond
(world-has-ended
(displayln "The world has ended: rain of fire imminent")
(rain-fire-from-sky 'yes-really))
...)
事实上,Scheme 有一个运算符,begin,它的全部目的是在只允许一个表达式的情况下允许一系列表达式。因此,例如,如果你想拥有一系列自然只有一个的表达式,你可以使用begin:
(if world-has-ended
(begin
(displayln "The world has ended: rain of fire imminent")
(rain-fire-from-sky 'yes-really))
(begin
(displayln "World has not yet ended, sorry for the frogs")
(rain-frogs-from-sky)))
然后,您可以将 cond 视为根据 if 和 begin 定义的:
(cond
(world-has-ended
(displayln "The world has ended: rain of fire imminent")
(rain-fire-from-sky 'also-rocks))
(world-has-nearly-ended
(displayln "The world has nearly ended")
(rain-frogs-from-sky 'also-some-fire)))
是相同的
(if world-has-ended
(begin
(displayln "The world has ended: rain of fire imminent")
(rain-fire-from-sky 'also-rocks))
(if world-has-nearly-ended
(begin
(displayln "The world has nearly ended")
(rain-frogs-from-sky 'also-some-fire))
#f))
至于为什么 cond 的语法被设计为有多个表达式的空间:这是一个历史问题。我认为有两件事有助于解释它:
-
(cond <t1> <e1> <t2> <e2> ...) 之类的语法读起来很痛苦,因为您需要计算正文中的表单数量,而 (cond (<t1> ...) (<t2> ...) ...) 则容易得多。
- 在 Lisp 的早期,那些只接触过 FORTRAN 和汇编程序(因为这几乎就是全部)的人倾向于编写类似于 FORTRAN 程序的程序,并且有很多命令式操作,边-效果、排序等。
cond 的语法允许这样做。