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