[racket] making Racket code more idiomatic

From: Cristian Esquivias (cristian.esquivias at gmail.com)
Date: Tue Apr 17 20:45:05 EDT 2012

Hi Joe,

Thanks for the tip on on values in for*/fold. That should be added to docs.

I took a stab at converting your example into something more
functional. I'm too new to Racket to claim it's idiomatic. I mostly
went in and tried to remove what I considered iterative idioms; things
like do, let loop, set!

(define (euler29c)
 ; calculate 99^2 - duplicates
 (- (sqr 99)
    (for/sum ([base '(2 3 5 6 7 10)])
      (define lst
        (for*/list ([exp (stop-before (in-naturals 1)
                                      (λ (exp) (> (expt base exp) 100)))]
                    [i (in-range 2 101)])
          (* i exp)))
      (- (length lst) (length (remove-duplicates lst))))))

- Cristian

On Tue, Apr 17, 2012 at 1:39 PM, Joe Gilray <jgilray at gmail.com> wrote:
> Cristian,
>
> One more thing, since for*/fold in your code only takes one accumulator, you
> don't need "values" at all.  Makes the code even shorter!
>
> -Joe
>
>
> On Tue, Apr 17, 2012 at 12:54 PM, Joe Gilray <jgilray at gmail.com> wrote:
>>
>> Hi Guys.
>>
>> Thanks for the education on for/fold and for*/fold.
>>
>> Cristian, your solution is very elegant, thanks, but unfortunately it does
>> generate all the numbers so is relatively slow and won't scale too well with
>> a and b.
>>
>> -Joe
>>
>>
>> On Tue, Apr 17, 2012 at 11:01 AM, Cristian Esquivias
>> <cristian.esquivias at gmail.com> wrote:
>>>
>>> I used Project Euler to try out new languages as well. Here was my
>>> attempt at Problem 29 for reference.
>>>
>>> (define (prob29 a b)
>>>  (set-count
>>>   (for*/fold
>>>       ([nums (set)])
>>>     ([i (in-range 2 (add1 a))]
>>>      [j (in-range 2 (add1 b))])
>>>     (values (set-add nums (expt i j))))))
>>>
>>>
>>> - Cristian
>>>
>>> On Tue, Apr 17, 2012 at 9:54 AM, Matthew Flatt <mflatt at cs.utah.edu>
>>> wrote:
>>> > Blindly refactoring the code, I'd use `for/fold' and add a `lst'
>>> > accumulator to `loop':
>>> >
>>> > (define (euler29c)
>>> >  ; calculate 99^2 - duplicates
>>> >  (- (sqr 99)
>>> >     (for/sum ([d '(2 3 5 6 7 10)])
>>> >       (let loop ([lst '()] [exp 1])
>>> >         (if (> (expt d exp) 100)
>>> >             (- (length lst) (length (remove-duplicates lst)))
>>> >             (loop (for/fold ([lst lst]) ([i (in-range 2 101)])
>>> >                     (cons (* i exp) lst))
>>> >                   (add1 exp)))))))
>>> >
>>> > At Tue, 17 Apr 2012 09:45:50 -0700, Joe Gilray wrote:
>>> >> Hi,
>>> >>
>>> >> To continue our conversation about creating idiomatic Racket code,
>>> >> here is
>>> >> some code I wrote last night to solve projecteuler.net problem #29:
>>> >>
>>> >> (define (euler29a)
>>> >>   ; calculate 99^2 - duplicates
>>> >>   (- (sqr 99)
>>> >>      (for/sum ([d '(2 3 5 6 7 10)])
>>> >>               (let ([lst '()])
>>> >>                 (let loop ([exp 1])
>>> >>                   (if (> (expt d exp) 100) (- (length lst) (length
>>> >> (remove-duplicates lst)))
>>> >>                       (begin
>>> >>                         (for ([i (in-range 2 101)]) (set! lst (cons (*
>>> >> i
>>> >> exp) lst)))
>>> >>                         (loop (add1 exp)))))))))
>>> >>
>>> >> It's fast (it avoids calculating a bunch of huge numbers), it gives
>>> >> the
>>> >> correct answer, so what's not to love?!
>>> >>
>>> >> Well, it starts off OK, but my eye stumbles over the following:
>>> >>
>>> >> 1) predeclaring lst and accessing it twice, related to each other
>>> >> 2) ugly single parameter named-let loop
>>> >> 3) ugly "begin" - not a big deal, but I just dislike when having to
>>> >> use
>>> >> begin
>>> >> 4) use of set!
>>> >>
>>> >> Here is a quick rewrite:
>>> >>
>>> >> (define (euler29b)
>>> >>   ; calculate 99^2 - duplicates
>>> >>   (- (sqr 99)
>>> >>      (for/sum ([d '(2 3 5 6 7 10)])
>>> >>               (let ([lst '()])
>>> >>                 (do ([exp 1 (add1 exp)])
>>> >>                   ((> (expt d exp) 100) (- (length lst) (length
>>> >> (remove-duplicates lst))))
>>> >>                   (for ([i (in-range 2 101)]) (set! lst (cons (* i
>>> >> exp)
>>> >> lst))))))))
>>> >>
>>> >> It solves #2 and #3 above, but it is still fundamentally clunky.
>>> >>
>>> >> 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.
>>> >>
>>> >> Thanks,
>>> >> -Joe
>>> >> ____________________
>>> >>   Racket Users list:
>>> >>   http://lists.racket-lang.org/users
>>> > ____________________
>>> >  Racket Users list:
>>> >  http://lists.racket-lang.org/users
>>
>>
>


Posted on the users mailing list.