我有以下代碼段。它工作的預期。Clojure:在合併和重複操作的上下文中排序映射的不規則行爲?
(use '(incanter.stats))
(defmacro dbg [body]
`(let [x# ~body]
(println "dbg:" '~body "=" x#)
x#))
(defn sorted-map-by-values
"create a map sorted in descending order, first by value, then by key"
[super-map & reverse]
(dbg "Start to sort")
(dbg super-map)
(let [compare-value (if (nil? reverse) 1 -1)]
(into (sorted-map-by
(fn [key1 key2]
(let [val1 (super-map key1) val2 (super-map key2)]
(cond
(= val1 val2) (.compareTo (str key2) (str key1)) ; use string representation of list, to overcome that there is no .compareTo for AarrySeq
(< (dbg val1) (dbg val2)) compare-value
:else (- compare-value)))))
super-map))
)
(def search (clojure.string/split "garbage stuff" #"\s"))
(def candidate (clojure.string/split "stuff" #"\s"))
(sorted-map-by-values (let [pairs-init (for [x search y candidate] [x y])]
(loop [pairs pairs-init distance-map {}]
(if (empty? pairs)
distance-map
(let [pair (sort (first pairs))
updated-map (if (nil? (get distance-map pair))
(merge distance-map {pair (apply incanter.stats/levenshtein-distance pair)})
distance-map)]
(recur (rest pairs) updated-map)))))
true)
但是,如果我在下文取代最後形式:
(let [pairs-init (for [x search y candidate] [x y])]
(loop [pairs pairs-init distance-map {}]
(if (empty? pairs)
distance-map
(let [pair (sort (first pairs))
updated-map (if (nil? (get distance-map pair))
(sorted-map-by-values ; <- move sorted-map-by-values to here
(merge distance-map {pair (apply incanter.stats/levenshtein-distance pair)})
true)
distance-map)]
(recur (rest pairs) (dbg updated-map))))))
然後我得到了一個錯誤:
java.lang.NullPointerException: null
Numbers.java:961 clojure.lang.Numbers.ops
Numbers.java:219 clojure.lang.Numbers.lt
(Unknown Source) user/sorted-map-by-values[fn]
AFunction.java:47 clojure.lang.AFunction.compare
PersistentTreeMap.java:311 clojure.lang.PersistentTreeMap.doCompare
PersistentTreeMap.java:298 clojure.lang.PersistentTreeMap.entryAt
PersistentTreeMap.java:278 clojure.lang.PersistentTreeMap.valAt
PersistentTreeMap.java:283 clojure.lang.PersistentTreeMap.valAt
RT.java:645 clojure.lang.RT.get
看來,在線路發生錯誤:
(< (dbg val1) (dbg val2)) compare-value
dbg trace爲fo llows:
Instarepl:
dbg: Start to sort = Start to sort
Instarepl:
dbg: super-map = {(garbage stuff) 7}
Instarepl:
dbg: updated-map = {(garbage stuff) 7}
Instarepl:
dbg: val1 = nil
Instarepl:
dbg: val2 = 7
當映射中只有一個映射時,不應該調用比較器函數。通過追蹤代碼,看起來錯誤實際發生在loop-recur的第二次迭代中,因爲updated-map值的dbg trace顯示第一次迭代包括從map-values-sorted-values返回成功,但我無法顯示第二個條目sorted-map-by-values
,似乎還有未知的另一個條目sorted-map-by-values
我猜那個排序映射可能是一個不同的類型,不能再次應用於排序值?
您能否介紹一些奇怪的行爲或者我懷念Clojure語言執行模型的某些部分,這與懶惰評估有關?
非常感謝!
請嘗試隔離您的問題案例並將其縮小爲幾行文本和代碼。 – 2014-10-11 10:22:24
我不能讓你的代碼的頭部或腳部,但你的'dbg'輸出顯示很清楚是什麼導致了錯誤:你的'val1'結尾爲'nil',不能用'<'到'7'。 – schaueho 2014-10-11 11:28:15