Honestly, if you're only doing self-recursion, what makes the recur special
form so inelegant? And the "loop" special form isn't very far removed from
the Scheme's named let, where you do something like

(let loop ((v1 init1) (v2 init2)) ... (loop))

I agree that it's not so nice that recur can *only* be used for
self-recursion and that there's no generalized tail call elimination, but
the cited examples don't depend on that anyway.

Also I note that the reduction of 2400 to 37 cycles took all of two
additional lines and a couple of type annotations (which is really not
unexpected), so---again, personally---it seems like "much less readable"
and "much less elegant" are fairly exaggerated.


On Tue, Jul 9, 2013 at 8:11 AM, Alexander Gunnarson <
alexandergunnar...@gmail.com> wrote:

> 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.
>
>
>



-- 
Ben Wolfson
"Human kind has used its intelligence to vary the flavour of drinks, which
may be sweet, aromatic, fermented or spirit-based. ... Family and social
life also offer numerous other occasions to consume drinks for pleasure."
[Larousse, "Drink" entry]

-- 
-- 
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