Hi,<div><br></div><div>To continue our conversation about creating idiomatic Racket code, here is some code I wrote last night to solve <a href="http://projecteuler.net">projecteuler.net</a> problem #29:</div><div><br></div>
<div><div>(define (euler29a)</div><div> ; calculate 99^2 - duplicates</div><div> (- (sqr 99) </div><div> (for/sum ([d '(2 3 5 6 7 10)])</div><div> (let ([lst '()])</div><div> (let loop ([exp 1])</div>
<div> (if (> (expt d exp) 100) (- (length lst) (length (remove-duplicates lst)))</div><div> (begin</div><div> (for ([i (in-range 2 101)]) (set! lst (cons (* i exp) lst)))</div>
<div> (loop (add1 exp)))))))))</div></div><div><br></div><div>It's fast (it avoids calculating a bunch of huge numbers), it gives the correct answer, so what's not to love?!</div><div><br></div>
<div>Well, it starts off OK, but my eye stumbles over the following:</div><div><br></div><div>1) predeclaring lst and accessing it twice, related to each other</div><div>2) ugly single parameter named-let loop</div><div>3) ugly "begin" - not a big deal, but I just dislike when having to use begin</div>
<div>4) use of set!</div><div><br></div><div>Here is a quick rewrite:</div><div><br></div><div><div>(define (euler29b)</div><div> ; calculate 99^2 - duplicates</div><div> (- (sqr 99) </div><div> (for/sum ([d '(2 3 5 6 7 10)])</div>
<div> (let ([lst '()])</div><div> (do ([exp 1 (add1 exp)])</div><div> ((> (expt d exp) 100) (- (length lst) (length (remove-duplicates lst))))</div><div> (for ([i (in-range 2 101)]) (set! lst (cons (* i exp) lst))))))))</div>
</div><div><br></div><div>It solves #2 and #3 above, but it is still fundamentally clunky.</div><div><br></div><div>Can someone help and teach us all some tricks? My instincts say it should be possible to use append-map, for/list and/or foldl to build a list of the duplicates then simply count them in the for/sum loop, but am still unable to do it.</div>
<div><br></div><div>Thanks,</div><div>-Joe</div>