Scheme 为什么';此球拍代码是否终止?

Scheme 为什么';此球拍代码是否终止?,scheme,racket,Scheme,Racket,我正在阅读有关懒惰评估和理解他们给出的一个基本示例有困难的文章 #lang racket (define (bad-if x y z) (if x y z)) (define (factorial-wrong x) (bad-if (= x 0) 1 (* x (factorial-wrong (- x 1))))) (factorial-wrong 4) 我有点困惑,为什么这个程序永远不会终止。我知道以下代码可以正常工作: (define (

我正在阅读有关懒惰评估和理解他们给出的一个基本示例有困难的文章

#lang racket
(define (bad-if x y z)
  (if x y z))
(define (factorial-wrong x)
  (bad-if (= x 0)
          1
          (* x (factorial-wrong (- x 1)))))

(factorial-wrong 4)
我有点困惑,为什么这个程序永远不会终止。我知道以下代码可以正常工作:

(define (factorial x)
  (if (= x 0)
      1
      (* x (factorial (- x 1)))))

(factorial 4)

所以我假设它与范围有关。我尝试了一步一步地调试,factorial Error即使在x映射到0时也会执行递归函数。

标准
if

(if test-expr then-expr else-expr)
将仅计算
然后expr
else expr
,具体取决于
测试expr
,因为如果
是特殊形式或基于特殊形式的语法扩展,这意味着它不遵循正常的计算规则

另一方面,如果是标准程序,则
错误。在这种情况下,Scheme首先计算两个表达式,因为它们是过程
bad if
的参数,然后才实际执行
bad if
。因此,即使对于x=0,
(*x(阶乘-1))
也将被计算,而这反过来将以无休止的循环计算
(*x(阶乘-2))
等等。

使用步进器

更具体地说:

  • 剪掉节目顶部的#lang球拍
  • 将语言级别更改为“中级学生”
  • 单击步骤按钮。仔细观察,看看哪里出了问题

那么在这两个示例中,
if
语句的行为不同吗?知道为什么吗?不知道if语句的行为方式完全相同。不同之处在于,如果这是一个过程,则称为bad。强制进行额外计算的是过程调用机制。为了进一步说明
if
不是一个过程,如果在REPL中输入
bad if
,您应该会看到类似
#
的内容,而如果输入
if
,则会出现
错误语法。这同样适用于
,因为这两种形式对何时计算其参数也有特殊的规则。