[racket] Performance of delay/force vs lambda/apply

From: Adolfo Pérez Álvarez (adolfo.pa at gmail.com)
Date: Sun Jul 15 07:19:04 EDT 2012

Hi everyone,

While playing around with delay/force I got some unexpected results.
It seems that the performance of delay/force is far worse than that of
an equivalent construction based on lambda/apply.

For example, this implementation of the tak function:

(define-syntax-rule (mdelay expr) (delay expr))
(define-syntax-rule (mforce expr) (force expr))

(define (tak x y z)
  (let ([a (mforce x)]
        [b (mforce y)])
    (cond [(<= a b) b]
          [else
           (tak (mdelay (tak (mdelay (sub1 a)) y z))
                (mdelay (tak (mdelay (sub1 b)) z x))
                (mdelay (tak (mdelay (sub1 (mforce z))) x y)))])))

(define (g n)
  (tak (mdelay n) (mdelay 0) (mdelay (add1 n))))

takes around 6 seconds to calculate (g 242501) on my machine:
> (time (g 242501))
cpu time: 5963 real time: 6005 gc time: 3980
242502

When redefining mdelay/mforce in terms of thunk/set!/apply:

(define-syntax-rule (mdelay expr)
  (let ([value #f])
    (thunk
     (or value
         (begin (set! value expr)
                value)))))

(define-syntax-rule (mforce expr) (expr))

> (time (g 242501))
cpu time: 1880 real time: 1894 gc time: 935
242502

Simplifying even further the definition of mdelay/mforce:

(define-syntax-rule (mdelay expr) (thunk expr))
(define-syntax-rule (mforce expr) (expr))

got me impressive results (comparable to a C implementation of the
same function):
> (time (g 242501))
cpu time: 597 real time: 602 gc time: 319
242502

Given that the compiler is so good optimizing function creation and
application, ¿Is there any reason to use delay/force over
lambda/apply? ¿Am I missing something here?

Regards.


Posted on the users mailing list.