clojurescript - Clojure newbie struggling with protocols -
clojurescript - Clojure newbie struggling with protocols -
i attempting build out concept of cursor in clojurescript, backed atom. cursor recursive zipper mechanism editing immutable nested associated datastructure.
i newbie @ clojure, can help me spot errors?
(defprotocol cursor (refine [this path]) (set [this value]) (value [this])) (defn- build-cursor* [state-atom paths] (reify cursor (set [this value] (swap! state-atom (assoc-in @state-atom paths value))) (refine [this path] (build-cursor* state-atom (conj paths path))) (value [this] (get-in @state-atom paths)))) (defn build-cursor [state-atom] (build-cursor* state-atom [])) (comment (def s (atom {:a 42})) (def c (build-cursor s)) (assert (= (value c) {:a 42})) (set c {:a 43}) ;; warning: wrong number of args (2) passed quiescent-json-editor.core/set @ line 1 <cljs repl> (assert (= (value c) {:a 43})) (def ca (refine c :a)) ;; warning: wrong number of args (2) passed quiescent-json-editor.core/refine @ line 1 <cljs repl> (assert (= (value ca) 43)) (set ca 44) (assert (= (value ca) 43)) )
i new clojure well, took stab @ , found 2 issues.
first, set
method clashes core library function (even though it's in cursor
protocol). sake of debugging, added underscore prefixes avoid this.
second, seems calling _set
on root cursor corrupts value. found assoc-in not handle empty path []
way might expect:
(assoc-in {} [] {:a 7}) ; {nil {:a 7}}
...so that's reason cond
in _set
.
here test code:
(ns cursory) (defprotocol cursor (_path [this]) (_root [this]) (_refine [this path]) (_set [this value]) (_value [this])) (defn- build-cursor* [state-atom paths] (reify cursor (_path [this] paths) (_root [this] @state-atom) (_set [this value] (cond (empty? paths) (reset! state-atom value) :else (assoc-in @state-atom paths value))) (_refine [this path] (build-cursor* state-atom (conj paths path))) (_value [this] (get-in @state-atom paths)))) (defn build-cursor [state-atom] (build-cursor* state-atom [])) (comment (def s (atom {:a 42, :b 84})) (def c (build-cursor s)) (_set c {:a 44, :b 88}) (_root c) (_path c) (_value c) (def ca (_refine c :a)) (_path ca) (_value ca) (_set ca 42) (get-in {:a 1 :b 2} []) (assoc-in {} [:a :b] 7) (assoc-in {} [] {:a 7}) (empty? []) )
clojure clojurescript
Comments
Post a Comment