Closed cemerick closed 11 years ago
Actually, the problem is more general; seems that many types of expressions produce a non-propagating cell:
(def root (cell (vec (range 4))))
; #<[object Object]>
;= nil
@root
;= [0 1 2 3]
(def cnt (cell (count root)))
; #<[object Object]>
;= nil
@cnt
;= 4
(swap! root conj 5)
;= [0 1 2 3 5]
@cnt
;= 4
The only sort of expression that appears to reliably work as an initial value is a symbol (naming an in-scope binding).
In your example there you have created formula cells when you intended to make input cells. You can only swap!
on input cells.
The short answer is:
(def root (cell '(vec (range 4))))
in your example above. Quoted expressions are evaluated in place and you obtain an input cell. Note that things like (cell {foo bar})
are transformed in the cell
macro into things like (cell (hash-map foo bar))
and hash-map
is then lifted, so if you are wanting an input cell containing a literal (non-reactive) vector, set, or map value then you must quote it. Note also that if you quote the expression then you'd need to explicitly deref foo
or bar
in that map if they are cells and you want the values they contain rather than the cells themselves.
The long answer follows in a minute...
Consider the following:
(def vec (cell first))
;=> #<object Object>
(def root (cell (vec (range 4))))
;=> #<object Object>
@root
;=> 0
(reset! vec rest)
;=> #'cljs.core/rest
@root
;=> (1 2 3)
This is why you'd have to quote the expression.
Got it, thanks. :-)
Idle suggestion: it might be clearer if input and formula cells had their own macros, at least for end-user consumption, since the compilation/evaluation semantics of each differ as you've described.
Sorry I didn't see your response till just now...
There is actually the #'tailrecursion.javelin/input
function that you can use to create an input cell, and then just use the cell
macro for formula cells.
Same interaction, but with the initial value taken "by reference":