[racket] static variables question

From: Joe Gilray (jgilray at gmail.com)
Date: Sun Feb 19 21:55:29 EST 2012

Hi Rodolfo,

Thanks for the suggestions.  Your re-factoring (no pun intended) of the
conds really cleaned things up.  Much appreciated.

About the unnecessary loops, good point, I simply changed to starting with
end set to 10 instead of 1000 and I think that helps a lot.  I know that
there are other gross inefficiencies as well (for example, if
primes-from-to gets called to just add a few primes to the list it is very
slow as it goes through the whole list.  A better implementation would
"know" that the values on storedlst are already checked and skip checking
them.

About the formatting: I really like to keep the code short on the screen,
so I'm not fond of your use of newlines, I find that it is easier to read
and debug code if you don't have to scroll down to see it.

Thanks again.  Latest code below (I found and fixed a howler of a bug in
primes-from-to).
-Joe

; function that returns a list of all integers between the two arguments
inclusive
(define  (interval-list m n)
  (if (> m n) '() (cons m (interval-list (+ 1 m) n))))

; sieve of erostosthenes
(define (sieve lst)
  (define (remove-multiples n lst)
    (if (null? lst) '()
        (if  (= (modulo (car lst) n) 0)
             (remove-multiples n (cdr lst))
             (cons (car lst)
                   (remove-multiples n (cdr lst))))))
  (if (null? lst) '() (cons (car lst) (sieve (remove-multiples (car lst)
(cdr lst))))))

; wrapper function for sieve, saves a list of primes for future calls
(define primes-from-to
  (let ([lastend 5] [storedlst '(2 3 5)])
    (lambda (start end)
      (cond [(<= lastend start) (set! storedlst (sieve (append storedlst
(interval-list lastend end))))]
            [(< lastend end) (primes-from-to lastend end)])

      ; storedlst now has all the primes needed
      (when (< lastend end) (set! lastend end))
      (filter (lambda (v) (and (<= start v) (<= v end))) storedlst))))

; function to create a list of prime factors of a number
; invoke as (factor n)
(define (factor n)
  (let loop-factors ([facts '()] [x n] [start 2] [end 10] [candidate-primes
(primes-from-to 2 10)])
    (define isqrtx (integer-sqrt x))
    (cond
      [(and (empty? candidate-primes) (>= end isqrtx))
       (if (= 1 x) facts (append facts (list x)))]
      [(empty? candidate-primes)
       ; attempt to pull in more primes in an efficient manner
       (set! start end)
       (set! end (* 2 end))
       (when (> (* 1.5 end) isqrtx) (set! end isqrtx))
       (loop-factors facts x start end (primes-from-to start end))]
      [(zero? (remainder x (first candidate-primes)))
       (loop-factors (append facts (list (first candidate-primes)))
(quotient x (first candidate-primes)) start end candidate-primes)]
      [else
       (loop-factors facts x start end (rest candidate-primes))])))



On Sun, Feb 19, 2012 at 5:33 PM, Rodolfo Carvalho <rhcarvalho at gmail.com>wrote:

> Hello Joe,
>
> I'd like to make a few suggestions also.
>
> ~ 1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
>
> I repeat what Neil V. said:
>
> Formatting-wise, you might consider generally putting newlines between
>> each of the three parts of an "if" form.  It's easier to distinguish the
>> parts at a glance, especially if the parts contain parens, and you can also
>> sometimes better see symmetries/asymmetries between the branches.
>
>
> And a similar rule would apply to let-, cond-, etc-clauses (i.e. the ones
> around square brackets []).
>
> So instead of
>
> (let ([a 1] [b 2] [c 3])
>    ...)
>
> I'd write for clarity:
>
> (let ([a 1]
>       [b 2]
>       [c 3])
>   ...)
>
>
>
> ~ 2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> The three `cond' uses are like `if's. They only have 1 test and an else
> clause. So considering the cond's and if's, the code branches like this:
>
> cond --- if ---- [1]
>   \          \---- [2]
>    \
>     \----- cond --- [3]
>             \
>              \------- cond ------ [4]
>                         \----------- [5]
>
>
> It is possible to replace a pattern like this:
>
> (cond
>    [..a..]
>    [else (cond
>                [..b..]
>                ...)])
>
> With this simpler:
>
> (cond
>    [..a..]
>    [..b..]
>     ...)
>
> That's one of the things that makes cond's different than if's...
>
> After applying the above, the branching structure becomes:
>
> cond --- if ---- [1]
>   |          \---- [2]
>   |------ [3]
>   |------ [4]
>   |------ [5]
>
>
>
> ~ 3 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> Using DrRacket's Debugger, I noticed that to compute (factor 4) the code
> was iterating many unnecessary times in the loop, until the
> candidate-primes list was exhausted.
>
> Looking back at the code, we see that there's only one way to stop the
> recursion, which is when (and (empty? candidate-primes) (>= end isqrtx))
> holds true.
> So even when we want to factorize small numbers we have to go through the
> entire list of computed primes.
> This suggests rethinking about the conditions...
>
>
> Here's the code with my changes:
>
>
>
> ; function to create a list of prime factors of a number
> ; invoke as (factor n)
> (define (factor n)
>   (let loop-factors ([facts '()]
>                      [x n]
>                      [start 2]
>                      [end 1000]
>                      [candidate-primes (primes-from-to 2 1000)])
>     (define isqrtx (integer-sqrt x))
>     (cond
>       [(and (empty? candidate-primes)
>             (>= end isqrtx))
>        (if (= 1 x)
>            facts
>            (append facts (list x)))]
>       [(empty? candidate-primes)
>        ; attempt to pull in more primes in an efficient manner
>        (set! start end)
>        (set! end (* 2 end))
>        (when (> (* 1.5 end) isqrtx)
>          (set! end isqrtx))
>        (loop-factors facts
>                      x
>                      start
>                      end
>                      (primes-from-to start end))]
>       [(zero? (remainder x (first candidate-primes)))
>        (loop-factors (append facts (list (first candidate-primes)))
>                      (quotient x (first candidate-primes))
>
>                      start
>                      end
>                      candidate-primes)]
>       [else
>        (loop-factors facts
>                      x
>                      start
>                      end
>                      (rest candidate-primes))])))
>
>
>
> []'s
>
> Rodolfo Carvalho
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20120219/0a31d613/attachment-0001.html>

Posted on the users mailing list.