简体   繁体   中英

Why does this recursive factorial lead to infinite recursion?

In one of my classes we are learning about functional programming, and I was told that this Racket code:

(define (my-if-bad x y z)
    (if x y z))

(define (factorial-bad n)
    (my-if-bad (= n 0) 1 (* n (factorial-bad (- n 1)))))

Will lead to infinite recursion. I understand this has to do with the fact that if statements are lazily evaluated, but I'm not sure exactly what that means for this scenario. Any help would be appreciated

First we have to clarify a few things,

Going forward I assume you are running in #lang racket

To be a little bit more accurate in terms of terminology, if statements are short-circuiting . What that means is for an expression (if bxy) the nested expression y will NOT evaluate if b is true . Similarly x will not evaluate if b is false.

However, that is not what is going on here (replace my-if-bad with regular if and everything works. Actually quite the opposite. What is happening is function arguments in Racket are evaluated once, eagerly at function application .

  • So essentially in order to call my-bad-if :

  • you first need to evaluate (factorial-bad (- n 1)) but

  • In order to evaluate (factorial-bad (- n 1)) you need to call my-bad-if

  • In order to call my-bad-if you need to evaluate (factorial-bad (- n 1))

and so on.

So the terminating case never stops the evaluation.

The best way to understand this is the following code

(define y 5)

(define a (begin
            (set! y (+ y 1))
            y))

(define (add x) (+ x  x))

There are two possibilities here, when calling add with a :

  1. Either this expands to
 (+ (begin (set! y (+ y 1)) y) (begin (set! y (+ y 1)) y))
  1. Or it expands to something like the following
(let [x (begin (set! y (+ y 1)) y)]
    (+ x x)

If it was the former, then

  1. The first x would set y= 5 + 1 = 6
  2. And then the second x evaluates y = 6 + 1 = 7
  3. We would get 13

Which is NOT the case.

So in your case by the time the if statement inside my-if-bad is hit, the values are already evaluated and the if 's short circuiting ability is meaningless

If you use the stepper in DrRacket you can see how the evaluation unfolds, and the n going -1, -2, -3...

Hope this helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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