Purely functional Sieve of Eratosthenes
Here's a small refinement on the technique. Wherin instead of looking for odd multiples  and removing them, you keep an extra reference in the incomplete sieve and look those specific multiples of the next prime. The first step is the same, looking for 3* (3, 5, 7, 9, ...,) but the second step you only look for 5*(5, 7, 11, 13, 17, 19, 23 , 25, ...)  

Overall a small speedup, but the upside is you will never be looking for a multiple that isn't either in the partial sieve or beyond it's range.  

(define (primes-up2 n)
  (cons 2 (unfold null?
                  car
                  (lambda (x) (remove-partial-seive-multiples (car x) (cdr x)))
                  (iota (quotient (- n 1) 2) 3 2))))

(define (remove-partial-seive-multiples n partials)
  (let recur ((xs partials)
              (ys partials)
              (i (* n n)))
    (cond ((null? xs) '())
          ((&lt; (car xs) i) (cons (car xs) (recur (cdr xs) ys i)))
          ((= (car xs) i) (recur (cdr xs) (cdr ys) (* (car ys) n)))
          (else (error "you ought not hit this")))))


This works as any multiple of n still in the partial sieve must also be coprime with all primes less than N. (of which the partial sieve is a complete list)

Now while not purely functional instead of keeping the result and reversing it in the end on your second iteration, you could implement it as a tail-modulo cons. While not stickly functional on the inside, it is functional from the outside. 

Another optimization would be to pass the maximum canidate to the remover of multiples and just return the xs when i is smaller than the last search.