lambdaschemeracketpredictionr5rs

Confused with behavior of this procedure


(CONTEXT)

I've defined a procedure that applies another one-argument procedure object to it's parameter twice. Take for example the procedure inc that adds 1 to it's argument, (double inc) will add two. hence ((double inc) 5) returns 7.

(THE PROBLEM)

I expected for (((double (double double)) inc) 5) to return 13. Since double double will apply a procedure 4 times and thus the most-left double will result in a the application of the one-parameter procedure 8 times. A lineair growth.

I'm wrong. Look below for what the procedure actually returns.

Clearly i'm missing something and there's a flaw in my understanding.

(define (double proc)
(lambda (y) (proc (proc y))))

(define (inc x) (+ x 1))

> ((double inc) 5)
7
> (((double double) inc) 5)
9
> (((double (double double)) inc) 5)
21
> (((double (double (double double))) inc) 5)
261    
> 

Solution

  • This should be fairly easy to deduct using both reason or substitution model.

    Reason:

    (double double)
    

    This is like double but twice, quadrouple. When applied with a function it will apply that function 4 times.

    (double (double double))
    

    This is doubling quadrouple. The result of quadrouple will be quadroupled making it 4*4. When applied with a function it will apply that 16 times.

    (double (double (double double)))
    

    This is doubling the previous one. Then the same again. 16*16 makes it apply the result 256 times.

    Thus (double double) is 2^2, (double (double double)) is (2^2)^2 and (double (double (double double))) is ((2^2)^2)^2 or 2^8 for short.

    This relates to lambda calculus where power is defined as λb.λe.e b or (lambda (b) (lambda (e) (e b)). Now double is the church numeral for 2. Do you see that you are doing ((2^2)^2)^2?

    Substitution

    Here are the expressions reduced. I sometimes jump steps later since it's pretty much the same that happens several times.

    ((double inc) 5)               ; ==>
    ((lambda (y) (inc (inc y))) 5) ; ==>
    (inc (inc 5))                  ; ==> 7
    
    
    (((double double) inc) 5)                   ; ==>
    (((lambda (y) (double (double y))) inc) 5)  ; ==>
    (((lambda (y) (double (double y))) inc) 5)  ; ==>
    ((double (double inc)) 5)                   ; ==>
    ((double (lambda (y) (inc (inc y)))) 5)     ; ==>
    ((lambda (y) ((lambda (y) (inc (inc y))) ((lambda (y) (inc (inc y))) y))) 5) ; ==>
    ((lambda (y) (inc (inc (inc (inc y))))) 5) ; ==>
    (inc (inc (inc (inc 5)))) ; ==> 9
    
    
    (((double (double double)) inc) 5)                                                                ; ==>
    (((double (lambda (y) (double (double y)))) inc) 5)                                               ; ==>
    (((lambda (y) ((lambda (y) (double (double y))) ((lambda (y) (double (double y))) y))) inc) 5)    ; ==>
    (((lambda (y) (double (double (double (double y))))) inc) 5)                                      ; ==>
    ((double (double (double (lambda (y) (inc (inc y)))))) 5)                                         ; ==>
    ((double (double (lambda (y) (inc (inc (inc (inc y))))))) 5)                                      ; ==>
    (inc (inc (inc (inc (inc (inc (inc (inc (inc (inc (inc (inc (inc (inc (inc (inc 5)))))))))))))))) ; ==> 21
    

    I'll leave the last one as an exercise.