On Fri, Dec 12, 2008 at 7:10 AM, Mark Engelberg
<mark.engelb...@gmail.com> wrote:
>
> Sometimes you use mutable state inside of a function to do some local
> temporary computation, and this state will never be visible outside of
> the function.  So externally speaking, the function is still a pure
> function.  Vars, Refs, and Atoms all seem to be reasonable choices for
> representing this kind of state.  What is the preferred style?
>
> For example, imagine you want to write the factorial function the
> imperative way.  Here are some options:
>
> ; functional way for reference
> (defn fact0 [n]
>  (reduce * 1 (range 1 (inc n))))
>
> ; use var
> (defn fact1 [n]
>  (with-local-vars [total 1]
>    (doseq [i (range 1 (inc n))] (var-set total (* @total i)))
>    @total))
>
> ;use ref
> (defn fact2 [n]
>  (let [total (ref 1)]
>    (doseq [i (range 1 (inc n))] (dosync (ref-set total (* @total i))))
>    @total))
>
> ;use atom
> (defn fact3 [n]
>  (let [total (atom 1)]
>    (doseq [i (range 1 (inc n))] (swap! total #(* % i)))
>    @total))
>
> Now I don't have a sufficiently recent build to test the atom version
> myself, but I tested the others.  The var version has a running time
> comparable to the functional version.  The ref version starts out
> noticeably slower, but after a few runs, hotspot gets it to where it
> runs almost as fast as the other two versions.  I imagine the atom
> performance would be somewhere between the var and ref performance.
> I'd be interested in hearing the details of atom performance from
> someone who can test that, but really, it seems like the performance
> is fairly similar here.  It becomes a question of style, mostly.  What
> do you guys think is the best style (assuming you really want to code
> something internally in an imperative way)?
>
> It is also instructive to compare the syntax of the three imperative
> versions.  I find it odd how similar, and yet different they each are.
>  I find it especially odd how you need with-local-vars to create a
> local var, rather than something like (let [total (var 1)]....) which
> would be more consistent with the other methods.  Granted, vars have
> some pretty bizarre semantics (for example, if you DID try to return a
> var outside of the function, or use it in a lazy-cons, you get weird
> results because the var essentially loses its binding outside of its
> lexical scope).  I'm guessing that's the point of with-local-vars
> syntax -- to flag that it's invalid outside of that block.  But still,
> it seems rather quirky.  I think I'd prefer local vars to be more
> consistent with ref syntax.
>
> That said, it seems to me like the var version is the best fit for
> hidden imperative behavior.  The transactional nature of ref is
> clearly unnecessary here, and the swapping behavior of atom only makes
> sense when multiple threads might be competing to alter atom.  Any
> other opinions?
>

Please don't do it.

If you really miss your loops, use loop/recur.

Rich

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

Reply via email to