I implemented a simple and not very efficent sieve of eratosthenes. Once for the built in racket-streams, and once for self defined streams. The only known difference to me is that the built in streams are evaluating the first item on call and not on construction. When evaluating the first 1000 primes on both implementations the self defined streams are running 10-20 times as fast. Is there any explanation?
(define (integers-starting-from-stream n)
(stream-cons n (integers-starting-from-stream (+ n 1))))
(define (stream-limit s limit)
(when (not (= limit 0)) (stream-limit (stream-rest s) (- limit 1))))
(define x (integers-starting-from-stream 2))
(define (divisible? x y)
(= (remainder x y) 0))
(define (sieve s)
(stream-cons
(stream-first s)
(sieve (stream-filter
(lambda (x)
(not (divisible? x (stream-first s))))
(stream-rest s)))))
(time (stream-limit (sieve x) 1000))
Or am i mising something that's affecting the performance?
(define-syntax-rule (s-delay exp)
(λ() exp))
(define (s-force delayedObject)
(delayedObject))
(define empty-s 'S-EMPTY-STREAM)
(define (s-empty? s)
(eq? s empty-s))
(define (s-first s)
(car s))
(define (s-rest s)
(s-force (cdr s)))
(define-syntax-rule (s-cons a b)
(cons a (s-delay b)))
(define (s-filter p s)
(cond ((s-empty? s) empty-s)
((p (s-first s))
(s-cons (s-first s)
(s-filter p (s-rest s))))
(else (s-filter p (s-rest s)))))
;;;;;;;;;;;;;;;;;;;;
(define (divisible? x y)
(= (remainder x y) 0))
(define (integers-starting-from n)
(s-cons n (integers-starting-from (+ n 1))))
(define (s-limit s limit)
(when (not (= limit 0)) (s-limit (s-rest s) (- limit 1))))
(define x (integers-starting-from 2))
(define (sieve s)
(s-cons (s-first s) (sieve (s-filter (lambda(x) (not (divisible? x (s-first s)))) (s-rest s)))))
(time (s-limit (sieve x) 1000))
car
I get only 5 times slower if I add it. My best guess is that JIT manages to constant fold the local code and perhaps not so good when it's in its own module. You might be interested in how to look at what the jit has done – Christinchristina