问题: 考虑一个不实现if结构的metacircular评估器,但只实现cond。路易斯理查德 声称如果没有必要,因为我们可以使用metacircular评估员评估以下程序:
(define (if predicate action alternative)
(cond (predicate action)
(else alternative)))
解释为什么这不起作用。特别是,假设您使用此if过程来定义阶乘:
(define (factorial n)
(if (= n 1)
1
(* n (factorial (- n 1)))))
使用上面的if语句评估(factorial 3)的结果使程序永远运行,但我不知道为什么。任何暗示都将不胜感激!谢谢!
答案 0 :(得分:1)
if
表达式是特殊表单,它不遵循与正常程序相同的评估规则 - 因此它不能通过程序实现,它必须使用语法转换(例如,使用宏或在您的情况下,更改底层解释器)。要看到这一点,请看这个简单的例子:
(if #t 'ok (/ 1 0))
=> 'ok
从未发生除零,因为只评估了表达式的'ok
部分。尝试使用if
的实现来评估相同的表达式 - 您将收到division by zero
错误。
现在你看,if
表达式的计算方式不同,具体取决于条件的值,只执行结果或只执行替代,但不能同时执行。这就是你的factorial
示例失败的原因 - 即使达到基本情况,另一个分支也会被执行,从而创建一个无限循环。
答案 1 :(得分:0)
请注意if/cond
是语法,而不是过程。使用if
语法并实际定义并尝试使用它有所不同。为了说明,请考虑以下事项:
(+ 1 (- 4 2))
这里我们有+
程序,它接受零个或多个数字并返回它们的总和。我们已经使用两个参数应用了该过程,第二个是表达式(- 4 2)
而不是值。请注意,这不会导致合同违规错误,并且实际评估为3.为什么?因为任何非值的参数首先被简化为值。所以表达式的评估结果如下:
(+ 1 (- 4 2))
=> (+ 1 2)
=> 3
回到定义的 if
过程,适用相同的规则,因为传递给函数的任何参数都不是值本身,在使用之前将减少为值if
程序。因此(factorial 1)
的评估变为:
(factorial 1)
=> (if (= 1 1) 1 (* 1 (factorial 0)))
=> (if #t 1 (* 1 (factorial 0)))
=> (if #t 1 (* 1 (if (= 0 1) 1 (* 0 (factorial -1)))))
=> (if #t 1 (* 1 (if #f 1 (* 0 (factorial -1)))))
=> ... (endless loop to negative infinity)
这与使用if
语法不同,其中评估被短路,这意味着else
案例仅在 的情况下进行评估谓词是假的。例如,
(if #t 1 (+ 1 'a))
不会因尝试添加数字和符号而抛出错误,因为它不会首先评估else-expression(因为谓词的计算结果为true)。因此,它返回1.