Moshe Erlbaum
Moshe Erlbaum

Reputation: 29

Delayed evaluation in Scheme

Given the following code:

(define (my-if condition iftrue iffalse) 
 (cond (condition iftrue) 
         (else iffalse)))

'-----example1
(my-if #t 
        (display "my if was true!")  
        (display "my if was false!")) 
(newline)
'-----example2
(my-if #t
        (display "my if was true!")
        (+ 2 3))

why would example 1 evaluate both parameters right away giving an output of

my if was true!my if was false!

yet in example 2 only

my if was true!

is the output?

Is this because display is never delayed but arithmetic operators are, or is it something else?

Upvotes: 1

Views: 246

Answers (2)

Mulan
Mulan

Reputation: 135287

Not sure if you can use lazy racket, but if so, this will work for you

#lang lazy

(define (my-if p t f)
  (cond [p t]
        [else f]))

(my-if #t (display 'true) (display 'false))

; => true

If you run it in normal racket ...

#lang racket

(define (if p t f)
  (cond [p t]
        [else f]))

(if #t (display 'true) (display 'false))

; => truefalse

Another way you could achieve laziness would be wrapping the arguments in lambdas:

#lang racket

(define (my-if p t f)
  ; this calls the correct function with zero arguments
  ((if p t f)))

; wrap the delayed arguments in zero-argument functions
(my-if #t (λ () (display 'true)) (λ () (display 'false)))

; => true

Upvotes: 1

Óscar López
Óscar López

Reputation: 236034

In both cases both arguments get evaluated - that's how procedures work, all the arguments to a function call are evaluated before the function body is executed, they are never delayed! (unless explicitly done so).

And that's why you can't implement my-if as a procedure, it has to be a special form, like if and cond, which only evaluate the part corresponding to a true condition, or the else part if none is true. Also, bear in mind that display just prints its argument on the console, but it doesn't return any value.

Your second example prints the message, but the addition too got executed anyway, it's just that its value wasn't returned because the first condition was true, so my-if returns the value of its first parameter, which is a value returned from the display call (before my-if is entered), which is void. For instance, see what this outputs on the console:

(my-if #t
       (+ 2 3)
       (display "my if was false!"))

As expected, both parameters get evaluated, but only the first one's value is returned:

my if was false! ; this got printed anyway
5                ; this is the value returned by `my-if`

Upvotes: 3

Related Questions