[racket] making Racket code more idiomatic

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

Oops:  I had scaled it to 1000 (also runs in under .1 seconds).  Here is
the right code:

(define (euler29d)
  (- (sqr 399)
     (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))))))



2012/4/18 Joe Gilray <jgilray at gmail.com>

> 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/720ce7bb/attachment.html>

Posted on the users mailing list.