Recursion 在Scheme中修改基本if表达式。为什么它会进入一个无限循环?

Recursion 在Scheme中修改基本if表达式。为什么它会进入一个无限循环?,recursion,lisp,scheme,infinite-loop,racket,Recursion,Lisp,Scheme,Infinite Loop,Racket,在Scheme中,我将基本的“if”命令修改为: (define (modified-if predicate then-clause else-clause) (if predicate then-clause else-clause)) 然后,我使用if的修改版本定义了一个简单的阶乘生成程序: (define (factorial n) (modified-if (= n 0) (* n (factorial (- n 1)))

在Scheme中,我将基本的“if”命令修改为:

(define (modified-if predicate then-clause else-clause)
  (if predicate
      then-clause
      else-clause))
然后,我使用if的修改版本定义了一个简单的阶乘生成程序:

(define (factorial n)
  (modified-if (= n 0)
               (* n (factorial (- n 1)))))

现在,当我调用上面的函数时,它进入一个无限循环。为什么会发生这种情况?

方案有着迫切的评估。这意味着,除非您使用的是委托给这种特殊形式的特殊形式(如
if
)或宏(如
cond
case
),否则将首先计算所有子表达式

那意味着你的表情

(modified-if (= n 0)
             1
             (* n (factorial (- n 1))))
首先计算
(*n(阶乘(-n1)))
,然后在运行
时修改
。(它可以在
(=n0)
之前或之后运行,但无论哪种方式,递归调用都会发生。)由于这是一个递归调用,这意味着您的程序将无限递归,最终将耗尽堆栈

这里有一个简单的例子:考虑这个:

(if #t
    (display "Yay!")
    (error "Oh noes!"))

因为
如果
是一种特殊形式,它只计算必要的分支,在这种情况下,它只计算
(显示“耶!”)
,而不计算
(错误“哦,不!”)
。但是如果您切换到使用
修改的if
,这两个表达式都将被计算,并且您的程序将引发错误。

使用DrRacket中的步进器查看修改的if的行为

选择“初学者”语言。输入以下程序,然后单击步进器图标:

(define (modif predicate then-clause else-clause)
  (if predicate then-clause else-clause))
(define (factorial n)
  (modif (= n 0) 1 (* n (factorial (- n 1)))))
(factorial 5)
现在,您可以一步一步地了解计算是如何发展的。请注意,
modif
遵循函数应用规则

有关DrRacket步进器的外观示例: