I got this strange situation: I'm using specter from clojurescript (hoplon) to build up a map in a function which when I feed it by hand works fine, but when I map values into it, it munges the map up. Is mapping it making it try and do the operations in parallel somehow? If so, how would I serialize them?
@vigilancetech can you show the code?
(defn stow-effect! [dev effect]
(let [x (sp/setval [:lights (id->type dev) (id->key dev)] effect (:root @ui-state))
y (sp/setval [:lights :all (id->key dev)] effect x)]
;(s/set-ui-state! @conn y)
;; there's some kind of issue with multi-processing here
(reset! ui-state (sp/setval [:root] y @ui-state))))
(defn checkbox-checked [device-type]
(let [x (map vals (sp/select [(n-device-records device-type) (sp/submap [:id :effect])] @data))]
(map #(apply stow-effect! %) x)
x))
when I feed it with the second function it makes multiple :root tags, but when I feed it by hand it works properly making only one
what is n-device-records
, id->type
, id->key
?
and what do you mean by "makes multiple :root tags"?
doesn't look like (map #(apply stow-effect! %) x)
will do anything
since map
is lazy
cljs.user> (s/set-ui-state! @d/conn nil )
nil
cljs.user> (s/get-ui-state @d/conn)
nil
cljs.user> @d/ui-state
{:root nil}
cljs.user> (d/checkbox-checked :fan)
(("Fan 0" "roll") ("Fan 1" "static_color") ("Fan 2" "none") ("Fan 3" "none") ("Fan 4" "none") ("Fan 5" "none"))
cljs.user> @d/ui-state
{:root nil}
cljs.user> (s/get-ui-state @d/conn)
nil
cljs.user> @d/ui-state
{:root nil}
cljs.user> (d/stow-effect! "Fan 0" "roll")
{:root {:lights {:all {:Fan_0 "roll"}, :fan {:Fan_0 "roll"}}}}
cljs.user> @d/ui-state
{:root {:lights {:all {:Fan_0 "roll"}, :fan {:Fan_0 "roll"}}}}
cljs.user> (d/stow-effect! "Fan 1" "static_color")
{:root {:lights {:all {:Fan_0 "roll", :Fan_1 "static_color"}, :fan {:Fan_0 "roll", :Fan_1 "static_color"}}}}
cljs.user> (d/stow-effect! "Fan 2" "none")
{:root {:lights {:all {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none"}, :fan {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none"}}}}
cljs.user> (d/stow-effect! "Strip 0" "police")
{:root {:lights {:all {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none", :Strip_0 "police"}, :strip {:Strip_0 "police"}, :fan {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none"}}}}
cljs.user> (s/set-ui-state! @d/conn nil )
nil
cljs.user> (s/get-ui-state @d/conn)
nil
cljs.user> @d/ui-state
{:root nil}
cljs.user> (map #(apply d/stow-effect! %) '(("Fan 0" "roll") ("Fan 1" "static_color") ("Fan 2" "none") ("Fan 3" "none") ("Fan 4" "none") ("Fan 5" "none")))
({:root {:lights {:all {:Fan_0 "roll"}, :fan {:Fan_0 "roll"}}}} {:root {:lights {:all {:Fan_0 "roll", :Fan_1 "static_color"}, :fan {:Fan_0 "roll", :Fan_1 "static_color"}}}} {:root {:lights {:all {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none"}, :fan {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none"}}}} {:root {:lights {:all {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none", :Fan_3 "none"}, :fan {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none", :Fan_3 "none"}}}} {:root {:lights {:all {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none", :Fan_4 "none", :Fan_3 "none"}, :fan {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none", :Fan_4 "none", :Fan_3 "none"}}}} {:root {:lights {:all {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none", :Fan_5 "none", :Fan_4 "none", :Fan_3 "none"}, :fan {:Fan_0 "roll", :Fan_1 "static_color", :Fan_2 "none", :Fan_5 "none", :Fan_4 "none", :Fan_3 "none"}}}})
cljs.user>
the repl realizes lazy sequences when it prints it
the way you wrote checkbox-checked
will not
better to write that sort of code with doseq
ah, okay
think that'll fix the multiple :root tag thing?
don't know what you mean by that
or what those other function references are
(defn n-device-records [type] [:lights sp/ALL #(= (:type %) type)])
(defn id->key [id] (keyword (st/replace id \space \_)))
(defn id->type [id] (let [x (st/split (st/lower-case id) #" ")]
(keyword (if (> (count x) 2)
(str (first x) \_ (second x))
(first x)))))
n-device-records navigates to all the records for a certain type of device. The others just convert from a string to a (spaceless) tag
thing is when I feed stow-effect! by hand, it builds ui-state properly with only one root tag, but when I map the values in, it screws it up, appending multiple root tags
could that be a specter thing? Or does that have something to do with map parallelizing the operation?
In fact, map can't "parallelize" anything.
Try replacing map
with mapv
, would it work?
nope, same thing
where is it appending multiple root tags?
when I do:
(mapv #(apply d/stow-effect! %) '(("Fan 0" "roll") ("Fan 1" "static_color") ("Fan 2" "none") ("Fan 3" "none") ("Fan 4" "none") ("Fan 5" "none")))
the result has multiple root tags, but if I feed those values in by hand, it works correctly, with only one root tag
its supposed to be {:root {:lights {:all {all records} {:fan {fan devices} :strip {strip devices.}}}}}
by result you mean the value of the atom ui-state
?
yes
what does it look like before and after?
the results are in the code display above.
I think you're reading the repl wrong
the sequence there is the result of map
which is showing the iterative changes to ui-state
the final value in that sequence is the final value of ui-state
I'd suggest you minimize the reproducible case, it's really hard to follow without the context and the CLJS at hand.
oh, so maybe it IS working and the repl is just printing out intermediate results
just do @ui-state
yup, you're right. When I check ui-state its correct. Thanks. That had me baffled
seems like most (lisp) repls I've used before only show the final return value
Since you are doing map
, you get the list of values anyway.
The final form of stow-effect!
is a reset!
call
reset!
sets a new value for an atom and returns that value too
so that's where the accumulation is happening; yeah, makes sense now, since I'm taking the side effect of that map rather than its result
Yep
Also, if you need map
for side effects only, you can use run!
instead
That's like mapc
in Lisp
btw, you can clean up this code with ATOM
and view
navigators
yeah, I'm a total noob to specter (and only slightly less so to clojure)
thanks guys! Really loving this tool