[racket] making Racket code more idiomatic

From: Joe Gilray (jgilray at gmail.com)
Date: Wed Apr 18 11:19:48 EDT 2012

Thanks for more food for thought.

Cristian, I really like the form of your solution with the answer being
produced at the bottom.  You also taught me about stop-before and
stop-after.  Very nice.

Maxim, Thanks for bringing up for*/set.  Your solution is elegant, but
unfortunately is relatively slow because it calculates all the numbers and
so doesn't scale very well with a and b (try upper = 1000).

Here's Cristian's code scaled to 400.  It runs in under .1 seconds:

(define (euler29d)
  (- (sqr 999)
     (for/sum ([base '(2 3 5 6 7 10 11 12 13 14 15 17 18 19 20)])
              (define lst
                (for*/list ([exp (stop-before (in-naturals 1) (λ (exp) (>
(expt base exp) 400)))]
                            [i (in-range 2 401)]) (* i exp)))
              (- (length lst) (length (remove-duplicates lst))))))

On Wed, Apr 18, 2012 at 5:33 AM, Maxim Romashchenko <max at anahoret.com>wrote:

> What about for*/set ?
>
> #lang racket
> (require racket/set)
> (define (generate-powers lower upper)
>  (for*/set ([a (in-range lower (add1 upper))]
>             [b (in-range lower (add1 upper))])
>            (expt a b)))
> (set-count (generate-powers 2 5))
> (set-count (generate-powers 2 100))
>
> Best regards, Maxim.
>
>
>
> On 2012-04-17 21:01, Cristian Esquivias 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<http://lists.racket-lang.org/users>
>>>>
>>> ____________________
>>>  Racket Users list:
>>>  http://lists.racket-lang.org/**users<http://lists.racket-lang.org/users>
>>>
>>
>> ____________________
>>   Racket Users list:
>>   http://lists.racket-lang.org/**users<http://lists.racket-lang.org/users>
>>
> ____________________
>  Racket Users list:
>  http://lists.racket-lang.org/**users <http://lists.racket-lang.org/users>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20120418/cb3efde0/attachment-0001.html>

Posted on the users mailing list.