繁体   English   中英

关于Scheme中cond表达式的问题

[英]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>21<expression1><expression2> 现在,如果<test>计算结果为真,则对后续表达式进行计算,并返回最终表达式的值。

因此,对于(cond (> 2 1) (else 2)) ,第一个<cond clause>(> 2 1) ,其中<test>是表达式> ,它的计算结果是一个过程,而不是#f因此是一个真正的价值。 然后依次对后续的表达式21求值,最终表达式的值为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM