[英]A question about cond expressions in Scheme
使用 Chez Scheme 9.5.5 版,请考虑cond
的两个示例:
(cond #t (else 2))
(cond (> 2 1) (else 2))
第一个表达式的计算结果为#t
,而第二个表达式的计算结果为1
。
似乎第一个表达式首先扩展为(cond (#t #t) (else 2))
,而第二个表达式在评估之前扩展为(cond ((> 2 1) 1) (else 2))
。
我的问题是:由于表达式(> 2 1)
是#t
,因此两个cond
表达式具有不同的值对我来说是违反直觉的。 以这种方式定义cond
是否有充分的理由?
编辑:我在 GNU Guile 3.0.1 中尝试了这两个表达式:
(cond #t (else 2))
会触发一个错误,它表示“cond: invalid clause in subform #t of (cond #t (else 2))”。(cond (> 2 1) (else 2))
计算结果为1
,与 Chez Scheme 9.5.5 相同。(cond (#t) (else 2))
计算结果为#t
。Edit2:使用 CHICKEN Scheme 5.1.0:
(cond #t (else 2))
触发了一个错误,它表示“在 (cond ...) 扩展期间 - 在 `cond' 中 - 不是一个正确的列表:#t”。(cond (> 2 1) (else 2))
的计算结果为1
,与来自Chez方案和GNU狡诈。(cond (#t) (else 2))
计算结果为#t
但带有警告,内容为“警告:cond' 中的#t' clause in
之后#t' clause in
:(else 2)”。与往常一样,阅读文档:
[test-expr]
test-expr的结果作为cond形式的结果返回。 test-expr 不在尾部位置。
所以第一个表达式返回#t
,正如预期的那样。
第二个表达式也返回#t
,我不确定你为什么说你得到1
。
如果你想返回一些特定的东西,你应该正确地形成它:
(cond [#t "hey it's true"])
--> "hey it's true"
但是,Chez 使用了一些 C-ism,我相信 integer-as-boolean 就是其中之一。 Chez 为#t
返回1
并不令我感到惊讶。 (免责声明:我个人没有使用过 Chez。)
第一个表达式在 Chez 9.5.4 中引发异常,这是最新版本:
> (cond #t (else 2))
Exception: invalid syntax (cond #t (else 2))
Type (debug) to enter the debugger.
我不确定为什么 9.5.5 在这方面会有所不同; 如果为真,这可能表明 9.5.5 中cond
的底层实现发生了变化。
在任何情况下, cond
形式都采用一个或多个<cond clause>
参数和一个可选的else
子句,其中<cond clause>
必须采用(<test> <expression1> ...)
; 即, <cond clause>
必须是包含一个测试形式和零个或多个表达式的括号表达式。 每个<cond clause>
按顺序求值,直到<test>
求值为真,之后依次求值后续表达式,并返回最终表达式的值。 当真正的<cond clause>
中没有后续表达式时,返回<test>
的值。
表达式(cond #t (else 2))
违反了这一点(因为第一个<cond clause>
格式错误)并且可能会引发语法错误,而 9.5.4 确实如此。 如果 9.5.5 在这种情况下没有引发语法错误,则可能应该向维护者提交错误报告。 再次注意,9.5.5 不是 Chez Scheme 的发布版本。
这在上面已经说明了,但我将在此处重复:当<test>
表达式的计算结果为真,并且<cond clause>
中没有后续表达式时,该子句的计算结果为<test>
的值。 因此,这有望根据 R6RS 工作,并且在 9.5.4 中按预期工作:
> (cond (#t) (else 2))
#t
这也是表达 OP 问题中第二个表达式的正确方法。 在这里,我修改了else
子句以返回3
以使其更清楚地评估哪个分支:
> (cond ((> 2 1)) (else 3))
#t
> (cond ((> 1 2)) (else 3))
3
问题中发布的未更改的第二个表达式在 9.5.4 中的行为与 OP 在 9.5.5 中报告的方式相同。 此行为与 R6RS 指定的完全一样:
> (cond (> 2 1) (else 2))
1
这里的第一个<cond clause>
是表达式(> 2 1)
,其中>
是<test>
, 2
和1
是<expression1>
和<expression2>
。 现在,如果<test>
计算结果为真,则对后续表达式进行计算,并返回最终表达式的值。
因此,对于(cond (> 2 1) (else 2))
,第一个<cond clause>
是(> 2 1)
,其中<test>
是表达式>
,它的计算结果是一个过程,而不是#f
因此是一个真正的价值。 然后依次对后续的表达式2
和1
求值,最终表达式的值为1
,然后返回。
请注意,表达式(> 2 1)
不会被计算为<test>
,因此在这种情况下(< 2 1)
行为应与(> 2 1)
相同:
> (cond (> 2 1) (else 3))
1
> (cond (< 2 1) (else 3))
1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.