Search code examples
schemelispracketlazy-evaluationsicp

How to implement "if" in normal order in Scheme?


I was learning SICP and I read about "the applicative order" and "the normal order". Then I played around the Exercise 1-6 and looked into the following code:

#lang racket
(define (p) (p))
(define (new-if test-expr then-expr else-expr)
  (cond (test-expr then-expr)
        (else else-expr)))

And when I evaluate (new-if (= 2 2) 5 (p)) , it goes into a dead loop because both the (= 2 2) and (p) are evaluated. So I wonder how to make this new-if in the normal order without changing the #lang racket into #lang lazy , but I can't figure it out.

> (new-if (= 2 2) 5 (p))
> 5

Solution

  • You cannot change the evaluation order of #lang racket. #lang lazy works since it is normal order. You can delay evalution with delay / force:

    #lang racket
    
    (define (p) (p))
    (define (new-if test-expr then-expr else-expr)
      (cond ((force test-expr) (force then-expr))
            (else (force else-expr))))
    (new-if (delay (= 2 2)) (delay 5) (delay (p))) ; ==> 5
    

    Without side effects you can replace delay with wrapping in a no argument lambda (thunk) and change force to apply the procedure.