To dramatise Gustavo's point, here's a quick comparison of some different
methods:

#lang racket

(collect-garbage)
(collect-garbage)
(collect-garbage)

(define as (build-list 1000000 (λ (n) (random 100))))
(define bs (build-list 1000000 (λ (n) (random 100))))

(define (f as bs [acc 0])
  (if (or (null? as) (null? bs))
      acc
      (f (rest as) (rest bs) (+ acc (* (first as) (first bs))))))

(time (f as bs))

(time
 (for/sum ([a as]
           [b bs])
   (* a b)))

(time
 (for/sum ([a (in-list as)]
           [b (in-list bs)])
   (* a b)))

(time (apply + (map (λ (a b) (* a b)) as bs)))

Results:

cpu time: 779 real time: 907 gc time: 111    ; Recursive function f
2449403808

cpu time: 437 real time: 434 gc time: 0       ; for/sum
2449403808

cpu time: 61 real time: 62 gc time: 0            ; for/sum with in-list
2449403808

cpu time: 307 real time: 334 gc time: 155    ; apply +
2449403808


To be honest I'm a little surprised how *slow* the hand-coded recursive
solution is!

Dan


On Fri, Jul 28, 2017 at 10:02 AM, Gustavo Massaccesi <gust...@oma.org.ar>
wrote:

> I agree with the in-list explanation, but I want to remark a few details.
>
> >> I don't really understand the (in-list ...) thing. This seems to be
> internal magic to me.
>
> `in-list` is not a function, it's a macro that looks like a function.
> `for` is another macro (that doesn't look like a function). But in
> Racket the macros are not just straightforward text substitution, they
> can do a lot of things. Most are simple, but some macros are very
> complex. For example `for` can examine some additional information
> stored in `in-list` and write very efficient code. I.e. magic, a lot
> of magic, but you can write your own magical `in-something`. The
> details are in https://docs.racket-lang.org/reference/for.html but
> it's not easy so I recommend reading it later after playing more with
> the simple macros.
>
> I looked at your solution with vectors. I think that vectors are not
> slower than lists, moreover, they should be slightly faster, but
> sometimes I guess wrong. The problem with your implementation is that
> it creates a lot of intermediate lists. For example in
>    (apply + (map (lambda (class-label) ...) class-labels)
> The intermediate list must be allocated and free after use, the values
> are scattered in memory so it may be slower to use them.
>
> Also, the compiler can write more efficient code for the + in (+ x y)
> than for the + in (apply + ...).
>
> The solution of Daniel use (for/sum ...) instead of (apply + (map ...)).
>
> There are a few places that can be rewritten. My recommendation for
> fast code is to try to avoid allocations when possible.
>
> Gustavo
>



-- 
*Daniel Prager*
Agile/Lean Coaching, Innovation, and Leadership
Profile: skillfire.co/dan
Startups: youpatch.com <http://www.youpatch.com>, skillfire.co
Twitter: @agilejitsu <https://twitter.com/agilejitsu>
Blog: agile-jitsu.blogspot.com
Linkedin: au.linkedin.com/in/danielaprager

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to