Clojure新手在协议上苦苦挣扎

时间:2014-10-04 20:01:24

标签: clojure clojurescript

我试图在一个由原子支持的clojurescript中构建concept of a Cursor。游标是一种类似于递归拉链的机制,用于编辑不可变的嵌套关联数据结构。

我是Clojure的新手,你能帮助我发现我的错误吗?

(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 to quiescent-json-editor.core/set at line 1 <cljs repl>
  (assert (= (value c) {:a 43}))
  (def ca (refine c :a)) ;; WARNING: Wrong number of args (2) passed to quiescent-json-editor.core/refine at line 1 <cljs repl>

  (assert (= (value ca) 43))
  (set ca 44)
  (assert (= (value ca) 43))


  )

1 个答案:

答案 0 :(得分:1)

我也是Clojure的新手,但我抓了一把,发现了两个问题。

首先,set方法与核心库函数冲突(即使它在Cursor协议中)。为了调试,我添加了下划线前缀来避免这种情况。

其次,似乎在根游标上调用_set会破坏该值。我发现assoc-in没有像您期望的那样处理空路[]

(assoc-in {} [] {:a 7})  
; {nil {:a 7}}

...这就是cond_set的原因。

这是我的测试代码:

(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? [])
  )