Scheme 实施方案';仅使用cond的s if子句
问题: 考虑一个不执行IF构造但只有一个COND的元计算评估器。路易斯·雷纳 声称if是不必要的,因为我们可以使用元循环评估器评估以下程序:Scheme 实施方案';仅使用cond的s if子句,scheme,lisp,racket,sicp,Scheme,Lisp,Racket,Sicp,问题: 考虑一个不执行IF构造但只有一个COND的元计算评估器。路易斯·雷纳 声称if是不必要的,因为我们可以使用元循环评估器评估以下程序: (define (if predicate action alternative) (cond (predicate action) (else alternative))) 解释为什么这不起作用。特别是,假设您使用此if过程来定义阶乘: (define (factorial n) (if (= n 1) 1
(define (if predicate action alternative)
(cond (predicate action)
(else alternative)))
解释为什么这不起作用。特别是,假设您使用此if过程来定义阶乘:
(define (factorial n)
(if (= n 1)
1
(* n (factorial (- n 1)))))
使用上面的if语句计算(阶乘3)的结果使程序永远运行,但我不知道为什么。对此的任何提示都将不胜感激!谢谢 a
如果表达式是一种特殊形式,它不会遵循与正常过程相同的求值规则-因此它不能由过程实现,它必须使用语法转换(例如,使用宏或在您的情况下,更改底层解释器)。要了解这一点,请查看以下简单示例:
(if #t 'ok (/ 1 0))
=> 'ok
由于只计算了表达式的'ok
部分,因此从未发生过被零除的情况。尝试使用的实现来计算相同的表达式,如果,则会得到除以零的错误
现在您可以看到,如果根据条件的值对表达式进行不同的计算,则只执行结果或只执行替代项,但决不能同时执行两者。这就是你的阶乘
示例失败的原因-即使达到基本情况,也会执行另一个分支,从而创建一个无限循环。如果表达式是一种特殊形式,它不会遵循与正常过程相同的求值规则-因此它不能由过程实现,它必须使用语法转换(例如,使用宏,或者在您的情况下,更改底层解释器)。要了解这一点,请查看以下简单示例:
(if #t 'ok (/ 1 0))
=> 'ok
由于只计算了表达式的'ok
部分,因此从未发生过被零除的情况。尝试使用的实现来计算相同的表达式,如果,则会得到除以零的错误
现在您可以看到,如果根据条件的值对表达式进行不同的计算,则只执行结果或只执行替代项,但决不能同时执行两者。这就是您的阶乘
示例失败的原因-即使达到基本情况,也会执行另一个分支,从而创建一个无限循环。请注意,if/cond
是语法,而不是过程。使用语法、实际定义语法和尝试使用语法是有区别的。为了说明,考虑以下内容:
(+ 1 (- 4 2))
这里我们有一个过程,它取零个或更多的数字,并返回它们的和。我们用两个参数应用了这个过程,第二个参数是表达式(-42)
,而不是值。请注意,这不会导致违反合同错误,实际计算结果为3。为什么?因为任何不是值的参数首先被简化为值。因此表达式的计算结果为:
(+ 1 (- 4 2))
=> (+ 1 2)
=> 3
回到您定义的if
过程,同样的规则也适用,因为传递给函数的任何参数(本身不是值)在使用if
过程之前都将被缩减为值。因此,(阶乘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
语法,其中求值是短路的,这意味着只有当谓词为false时才会求值else
情况。比如说,
(if #t 1 (+ 1 'a))
willnot在尝试添加数字和符号时抛出错误,因为它首先不会计算else表达式(因为谓词的计算结果为true)。因此,它返回1。注意,if/cond
是语法,而不是过程。使用语法、实际定义语法和尝试使用语法是有区别的。为了说明,考虑以下内容:
(+ 1 (- 4 2))
这里我们有一个过程,它取零个或更多的数字,并返回它们的和。我们用两个参数应用了这个过程,第二个参数是表达式(-42)
,而不是值。请注意,这不会导致违反合同错误,实际计算结果为3。为什么?因为任何不是值的参数首先被简化为值。因此表达式的计算结果为:
(+ 1 (- 4 2))
=> (+ 1 2)
=> 3
回到您定义的if
过程,同样的规则也适用,因为传递给函数的任何参数(本身不是值)在使用if
过程之前都将被缩减为值。因此,(阶乘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
语法,其中求值是短路的,这意味着只有当谓词为false时才会求值else
情况。比如说,
(if #t 1 (+ 1 'a))
willnot在尝试添加数字和符号时抛出错误,因为它首先不会计算else表达式(因为谓词的计算结果为true)。因此,它返回1。我在阶乘循环中打印了n,n从3减少到负无穷大。即使在几个循环后n已经等于0,程序仍然没有停止。我在阶乘循环中打印了n,n从3减少到负无穷大。即使n在几个循环后已经等于0,程序仍然没有停止。谢谢!这绝对有帮助。谢谢!这绝对有帮助。