Chubbles
Chubbles

Reputation: 123

How can I delay/lazy evaluate an argument to a function in Racket?

I'm am staying within #lang racket. I am trying to figure out how to delay a function argument from being evaluated - I cannot change the argument being passed in. For example, say I wanted to pass in do something like this:

(define (a e) 6)

Then I want to call a with this argument

(a (/ 1 0))

How can I delay the evaluation of this argument?

I tried doing something like (in the function a):

(define (a e) (define E (lambda () e)) 6)

But this still evaluates the argument first. Any advice?

Upvotes: 2

Views: 1585

Answers (1)

Sylwester
Sylwester

Reputation: 48745

#lang racket is an eager language, but as it's earlier generation was a R5RS Scheme it still has R5RS compatible delay and force:

(define (test delayed-e) 6)
(test (delay (/ 1 0)))
; ==> 6

Without the special forms you could do:

(test (thunk (/ 1 0)))
; ==> 6

;; the same as
(test (lambda () (/ 1 0)))
; ==> 6

Notice in both you need to do it when you call the functions since you need to wrap the values before the language evaluates them. In a lazy language like #lang lazy you can write the code naively and it will do the correct thing.

#lang lazy

(define (test e) 6)
(test (/ 1 0))
; ==> 6

Now an implementation of #lang lazy would be to have macro that decorates with delay and force so the core might be the same with just slightly different surface language. If there was as easy to use lazy evaluation in an eager language we wouldn't have the use for lazy languages.

EDIT

Macros are a way to do computation on the actual code. Thus if you made your function a macro instead you could have it turn into whatever you'd like:

(define-syntax test 
  (syntax-rules ()
    ((_ ignored-edpression) 6)))

(test (/ 1 0))
; ==> 6 

Not it's important to know that this replaces the code with 6. You could instead make it wrap:

(define-syntax define-lazy
  (syntax-rules ()
    ((_ (name args ...) body ...)
     (begin
       (define (impl args ...)
         body ...)
       (define-syntax name
         (syntax-rules ()
           ((_ margs (... ...)) (impl (delay margs) (... ...)))))))))

(define-lazy (test e) 6)
(test (/ 1 0))
; ==> 6

If you look at what this expands (test (/1 0)) to it will look like the first example. Unlike the lazy languages you would need to force the arguments in the body explicitly though.

(define-lazy (my-if p c a)
  (if (force p)
      (force c)
      (force a)))

(my-if (< 3 4) 10 (/ 1 0))
; ==> 10

Upvotes: 2

Related Questions