Hello everyone! It's great to be here with all you fellow Clojurians. Just 
so you know, this is my first post on this group, so don't shoot me if it's 
terrible ;) 

As background, I've been working through SICP and have been loving Scheme. 
It's almost breathtaking how elegant and clean the code can be (I had some 
moments 
like xkcd goes off abou <http://xkcd.com/224/>t). Of course, though Scheme 
is beautiful and simple, everyone knows that it's not especially practical, 
in general. I love the Lisp paradigms but I'm not really a fan of CL so I 
did some looking around and stumbled upon Clojure. It seems that Clojure 
really has a lot going for it between shockingly easy concurrency support 
and Java interop, among other things. But one thing that's been bothering 
me is that it seems like to optimize performance in Clojure, you have to 
sacrifice some elegance.

*Example 1: Tail-call recursion*

*Scheme*
One example would be tail-call recursion. For instance, normally in Scheme 
I'd naively implement an iterative exponent function like this:

(define (expt x n)

        (cond ((= 0 n) 1)

              ((= 1 n) x)

              (else (expt (* x x) (- n 1)))))

Pure. Simple. Beautiful. (Not that I'm the best Scheme programmer ever, but 
to me it looks beautiful, and it conforms well to the base of the problem. 
You get the point.)

*Clojure*
Of course, tail-call recursion is not possible with JVM, so Clojure uses a *
recur* macro in place of direct recursive function calling. It avoids 
blowing the stack as quickly but it's still not 100% "mathematically pure" 
in the way Scheme tends to be.

An added gripe is that the* else *form within *cond *in Clojure uses a 
keyword, *:else*, instead of the more consistent parenthetical form used in 
Scheme. I suppose that's to make it less "Lispy." But it just ends up 
making it a little less elegant.

*Example 2: Type casting*
*
*
Some have said that Clojure can be somewhat slow (as with all Lisps). I'm 
not sure how true this is, but I stumbled on an example on John Lawrence 
Aspden's 
blog<http://www.learningclojure.com/2013/02/clojure-is-fast-is-clojure-still-fast.html>.
 
He wrote a program to implement Euler's method like so:

*First Solution*

(defn f [t y] (- t y))

(defn solveit [t0 y0 h its]
  (if (> its 0) 
    (let [t1 (+ t0 h)
          y1 (+ y0 (* h (f t0 y0)))]
      (recur t1 y1 h (dec its)))
    [t0 y0 h its]))


He points out that "if this was an assembly language program that worked the 
way you'd expect, each loop would take 7 cycles." So he tests it for Clojure. 
The result? On his netbook with Clojure 1.4: 2400 cycles. As he says, "We're 
looking at a slowdown of about 300 times over what we could probably achieve 
coding in assembler or in C with a good optimizing compiler." That's not 
surprising, I suppose, but it's still a little disheartening. After all, you 
want your language to be fast, right? Well, after a few iterations, he manages 
to reduce the cycles way down - all the way down, in fact, to 37, which is 
quite a feat. Like so:


*Final Solution*

(defn solveit-4 [t0 y0 h its]
  (let [zero (long 0)]
    (loop [t0 (double t0) y0 (double y0) h (double h) its (long its)]
      (if (> its zero) 
        (let [t1 (+ t0 h)
              y1 (+ y0 (* h (- t0 y0)))]
          (recur t1 y1 h (dec its)))
      [t0 y0 h its]))))


But the thing is, between the *recur *macro, explicit typecasting, and the 
*loop* construct, yes, you have a very significant performance increase, but it 
the code's gotten bigger, much less readable, and much less elegant.


*The bottom line*

*
*

My idea, which is probably very naive, but one which I'm curious about, is:

*Is it possible to have some sort of set of automatic-optimizing macros that 
work on Clojure code to preserve elegance while maximizing performance?*

*
*

In theory, it would be kind of an abstraction layer. There would be one file 
that would store the code that gets read and another output file that stores 
the code that actually gets evaluated by the REPL, and a set of macros to 
optimize the "front-end", "abstracted" file into the output, "nuts-and-bolts" 
file to be evaluated by the REPL. Probably this would be a very intensive 
process - I don't know. But maybe it's worth the trouble after all to save a 
ton of programmer-hours by increasing readability.


Thoughts?

-- 
-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to