[racket] Performance of delay/force vs lambda/apply
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.