Not a good thing. The word 'must' is the glaring red flag.
Not a good thing. The word 'must' is the glaring red flag.
And it's as simple as e.g. (dosync (ref-set ref newval)). In fact, if you find yourself doing it a lot (don't, please!) then define yourself a little function (defn rset [r v] (dosync (ref-set r v))).
Must isn't that bad of a word, and it's a Lisp: what kind of boilerplate do you expect to write? I prefer it going on none.
It's definitely worth checking out, and if you need state, and you'll need it rarely if at all, you're better served using the built-in STM and the wonderful functions that allow you to manage it (like add-watch; what a lifesaver in a state-heavy app like a GUI) to handle the mess.
There are times when the imperative style is more natural.
By this I merely meant, "I don't understand what you are saying". Hope that was clear.
besides, i think even truly single-assignment languages seem to have a place, just ask those crazy erlang guys ;)
the way i read clojure's philosophy around state is: "you can fuck up the concurrency if you want but we're going to make it really hard to do it by mistake".
What I was looking for can be done with atoms, and is made more like traditional lisp mutation by defining a "st!" (or maybe "zet!" is a better name).
(defn st! [atm v]
(swap! atm (fn [_] v)))
Now making ordinary lisp clojures is reasonable: (def fns
(let [c (atom 0)]
{:add (fn [x] (st! c (+ @c x)))
:mlt (fn [x] (st! c (* @c x)))}))
> ((get fns :add) 3)
3
> ((get fns :add) 3)
6
> ((get fns :mlt) -5)
-30
Though I sure could do without the calls to 'atom' and @. Referencing and dereferencing is for C programmers. Maybe using swap! directly is better after all. (def fns
(let [c (atom 0)]
{:add (fn [x] (swap! c #(+ % x)))
:mlt (fn [x] (swap! c #(* % x)))}))But what I really want it something that doesn't require dereferencing syntax:
(zet! c (* c x))I'm not sure wether this is good style. Probably not.
Edit: Bah. Fixed an error.
Sadly, as far as I know, you need to roll your own tree-reduce.
(swap! c (partial * 2))
on two separate threads, c will always end up 4x the original value.These limitations exist for a reason.
(swap! c * 2)