Dear Bob, My sense is that there are, perhaps, two questions: first, what's the advantage of Racket when faced with a "prosaic computational task where ... my brain defaults to writing in something like C"?; and second, how to advocate for Racket when Python (appears to be) "quite a bit faster".
I’m interested in both of these because I am trying to understand where my colleagues are coming from (and possibly changing their minds). On the first question, this discussion has perhaps produced four different versions of the prime-counting program: 1. Python (using a for-loop); 2. Racket (using accumulator-passing style); 3. Racket (using a for-loop); 4. Racket (using map/filter). (Actually, I can’t find an example of (4) in the email chain, but there’s one at the bottom of this email.) It’s certainly been educational for me to see all four. On reflection, do you still have the sense that (1) is the “most natural”? On the second question, let me report some rough-and-ready timings on my machine for counting the number of primes of the form 2^n + 3 for n < 1000 (the code is at the end of the email): Python: 265 ms Racket (filter/map version): 760 ms Racket (for loop version): 670 ms. My own feeling is that /for this particular application/, there's just not that much difference. I strongly suspect that all of the difference comes from the implementation of the primality testing functions. It turns out that, for sufficiently large numbers, both sympy and math/number-theory actually check for pseudoprimality. So there may be implementation-dependent details (which I don't understand) that are different, such as the probability that a composite number is incorrectly identified as a prime. Indeed, maybe the answer to your second question is that, I rather suspect, Racket is quite a bit faster than Python, so one could reasonably turn the question around. I implemented a cheap-and-cheerful, deterministic primality test (from Wikipedia, code again at the end of the email). I’m pretty sure I’ve written essentially identical code in Python and Racket: Python using `while` and mutation; Racket using `for/and`. Here are the times I get for testing the primality of 2^55 + 3 (which is in fact prime): Python: 7 s Racket: 0.8 s Make of that what you will! Best regards, James === Python, count special primes === import timeit import sympy def count_special_primes(N): count = 0 for n in range(N): if sympy.isprime(2 ** n + 3): count = count + 1 return count print(timeit.timeit('count_special_primes(1000)', globals = globals(), number = 1)) === Racket, count special primes === #lang racket (require math/number-theory) ;; "filter/map" variation ;; Count primes of the form 2^n + 3 for n < N (define (count-special-primes N) (define (f n) (+ (expt 2 n) 3)) (length (filter prime? (map f (range N))))) (time (count-special-primes 1000)) ;; “for-loop" variation (define (count-special-primes/quicker N) (define (f n) (+ (expt 2 n) 3)) (for/sum ([n (in-range N)]) (if (prime? (f n)) 1 0))) (time (count-special-primes/quicker 1000)) === Python, primality test === Import timeit import math ## Quick and dirty test for primality ## from https://en.wikipedia.org/wiki/Primality_test def is_prime(n): if n <= 3: return (n > 1) elif (n % 2 == 0) or (n % 3 == 0): return False else: k = 5 k_max = int(math.sqrt(n)) + 1 while k < k_max: if (n % k == 0) or (n % (k + 2) == 0): return False k = k + 6 return True print(timeit.timeit('is_prime(2 ** 55 + 3)', globals = globals(), number = 1)) === Racket, primality test === ;; integer? -> integer? ;; Quick-and-dirty test for primality ;; from https://en.wikipedia.org/wiki/Primality_test (define (prime/slow? n) (if (<= n 3) (> n 1) (if (or (= (modulo n 2) 0) (= (modulo n 3) 0)) #f (prime-aux n)))) ;; Test for primality assuming n > 3 and divisible by neither ;; 2 nor 3 (define (prime-aux n) (let ([k-max (ceiling (sqrt n))]) (for/and ([k (in-range 5 n 6)] #:break (> k k-max)) (not (or (= (modulo n k) 0) (= (modulo n (+ k 2)) 0)))))) (time (prime/slow? (+ 3 (expt 2 55)))) > On 11 Jul 2019, at 02:36, Bob Heffernan <bob.heffer...@gmail.com> wrote: > > On 19-07-10 02:46, Maciek Godek wrote: >> A while ago, I wrote a booklet which used almost the same problem to >> introduce to, what you called nicely in the title of this thread, "thinking >> in Scheme", so if you're interested, you may want to check out the first >> chapter ("Introduction"): > > Maciek, > > Thank you for your reply. > > I skimmed through your booklet some time ago. (I too dislike the R > language, although some attempts have been made in recent years to make > it less awful). I read through the introduction again this morning and > enjoyed it. > > The reason I like racket (and scheme-like languages in general) is that > they encourage the style of programming you are advocating (I think) > where the program is expressive and can be read and appreciated by > humans. In theory, my favourite style of programming is one that is > elegant and readable by humans. > > My original email had to do with the problem of when this comes into > conflict with a prosaic computational task where my main aim is simply > to get the job done efficiently and my brain defaults to writing the > program in something like C. > > For instance, another way of writing something like my original program > might be something like: > > (define (f n) (- (expt 2 n) 3)) > (define (good? n) (and (positive? n) (prime? n))) > (length (filter good? (map f (range 1 100)))) > > which is, I think, fairly expressive. It is still, however, relatively > inefficient. A python programmer might write something like > > count = 0 > for n in range(1, 1000): > if 2 ** n - 3 >= 0 and isprime(2 ** n - 3): > count += 1 > > print(count) > > and happily report that her program ran quite a bit faster than mine. > > I'm not sure how I'd advocate for Racket (or scheme) in a situation like this. > > Regards, > Bob > > -- > 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. > To view this discussion on the web visit > https://groups.google.com/d/msgid/racket-users/20190711013633.nm2jlznhzwibhsli%40bob-cit. > For more options, visit https://groups.google.com/d/optout. -- 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. To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/6E47B95D-D18B-4265-B6E6-AFA60CC2112E%40gmail.com. For more options, visit https://groups.google.com/d/optout.