1

对于 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 Scheme 和 GNU Guile 一样。
  • 该表达式的(cond (#t) (else 2))计算结果为#t但带有一个警告,上面写着“警告:#t' clause in cond 之后的子句:(else 2)”。
4

2 回答 2

1

第一个表达式在 Chez 9.5.4 中引发了一个异常,这是最新版本

> (cond #t (else 2))

Exception: invalid syntax (cond #t (else 2))
Type (debug) to enter the debugger.

我不确定为什么 9.5.5 在这方面会有所不同;cond如果属实,这可能表明9.5.5中的底层实现发生了变化。

在任何情况下,表单cond需要一个或多个<cond clause>参数,以及一个可选else子句,其中 a<cond clause>必须是(<test> <expression1> ...); 即,a<cond clause>必须是一个带括号的表达式,包含一个测试表单和零个或多个表达式。每个<cond clause>都按顺序计算,直到 a<test>计算结果为真,之后按顺序计算后续表达式,并返回最终表达式的值。如果 true 中没有后续表达式,则返回<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

需要明确的是:<cond clause>上面第一个表达式中的第一个是((> 2 1)),其中包含. 该测试的计算结果为,并且由于该子句中没有后续表达式,因此该子句返回。第二个表达式有as its , 和. 此测试评估为,因此评估继续进行下一个, ,它返回。<test> (> 2 1)#t#t((> 1 2))<cond clause><test> (> 1 2)#f<cond clause>(else 3)3

问题中发布的未更改的第二个表达式在 9.5.4 中的行为方式与 OP 针对 9.5.5 报告的方式相同。此行为与 R6RS 指定的完全相同:

> (cond (> 2 1) (else 2))
1

这里的第一个是<cond clause>形式(> 2 1),其中,和>是and 。现在,如果计算结果为 true,则计算后续表达式,并返回最终表达式的值。<test>21<expression1><expression2><test>

因此,对于(cond (> 2 1) (else 2)),第一个<cond clause>(> 2 1),其中<test>是表达式>,它的计算结果是一个过程,它不是#f一个真值,因此是一个真值。然后依次对后面的表达式2和求值,最终表达式的值为,然后返回。11

请注意,此处的表单(> 2 1)未评估为 a <test>;单独的表单>被评估为<test>. 此外,在这种情况下的(< 2 1)行为应该相同。(> 2 1)事实上,只要第一个元素的计算结果不为 ,任何类似的形式都会表现得与此相同#f

> (cond (> 2 1) (else 3))
1
> (cond (< 2 1) (else 3))
1
> (cond ('any-truthy-thing 2 1) (else 3))
1

版本更新

在我发布这个答案几天后,新版本的 Chez 发布了。请注意,OP 使用的是 9.5.5,它从来都不是发布版本(大概 OP 从源代码构建了 9.5.5)。新版本是 9.5.6。我没有从源代码构建 9.5.5 来测试任何这些;我当时使用的是当前版本,即 9.5.4。我现在已经在我的主机上更新到 9.5.6,并且 9.5.4 和 9.5.6 对于 OP 询问的表达式具有相同的行为。第一个 OP 表达式是(cond #t (else 2)),OP 发现它的计算结果是#t。Chez 在这种情况下不应返回#t但需要引发语法错误,如我上面的回答中所述。9.5.5 的维护者提出了一个问题,但该问题无法重现。第二个表达是(cond (> 2 1) (else 2)); 这个表达式被 9.5.4、OP 的 9.5.5 正确处理,现在也被当前的 9.5.6 版本处理。

于 2021-11-02T21:33:49.653 回答
-1

与往常一样,阅读文档

[test-expr]

test-expr的结果作为cond形式的结果返回。test-expr 不在尾部位置。

所以第一个表达式#t按预期返回。

第二个表达式也返回#t,我不确定你为什么说你得到了1

如果你想返回特定的东西,你应该正确地形成它:

(cond [#t "hey it's true"])

--> "hey it's true"

然而,Chez 使用了一些 C-isms,我相信整数作为布尔值就是其中之一。1Chez 回来了并不令我感到惊讶#t。(免责声明:我个人没有使用过 Chez。)

于 2021-11-01T01:31:46.320 回答