If you're interested in specially the overhead of combinator style,
then your example still understates the overhead compared to relatively
cheap operations.

In addition to Matthias's change to get rid of `apply', I've revised
your program (see below) to replace `first' and `rest' with `car' and
`cdr' (which don't have to check that they're given lists) and to lift
out the list creation (which becomes significant). With those changes,
I get

 cpu time: 1655 real time: 1668 gc time: 1546 ; list creation
 cpu time: 422 real time: 426 gc time: 41
 10000000
 cpu time: 60 real time: 60 gc time: 0
 10000000

The direct version is faster because the compiler can see the loop, so
it can produce code with fewer jumps and less allocation of
intermediate closures. I suppose that the general rule is that the
compiler is more effective when you can use constructs that say more
directly what you want.

Compilers can't easily see through a Y combinator, and a factor of 8 or
so difference is probably typical for Lisp compilers. (I tried Ikarus
and Gambit to double check, and performance was about the same as with
Racket.)

----------------------------------------

#lang racket
(define-syntax U
  (syntax-rules ()
    [(_ f) (f f)]))
(define-syntax define/comb
  (syntax-rules ()
    [(_ comb name (arg . args) f)
     (define name 
       (comb (λ (name) (λ (arg . args) f))))]))

(define (Z f)
  (U (λ (g) (λ (x y)
              ((f (U g)) x y)))))

(define/comb Z comb-sum (l t) 
  (if (null? l) t (comb-sum (cdr l) (+ t (car l)))))

(define (sum l t)
  (if (null? l) t (sum (cdr l) (+ t (car l)))))

(define l (time (make-list 10000000 1)))
(time (comb-sum l 0))
(time (sum l 0))

_________________________________________________
  For list-related administrative tasks:
  http://lists.racket-lang.org/listinfo/users

Reply via email to