使用postwalk将向量更改为列表

时间:2014-06-17 02:02:04

标签: clojure

(postwalk #(do (println "visiting:" %)
               (if (vector? %)
                 (seq %)
                 %))
          [:title {:bu "hu"}])

我的期望(没有printlns):(:title {:bu "hu"})

我得到了什么:

visiting: :title
visiting: :bu
visiting: hu
visiting: [:bu hu]
Stack trace of root exception is empty; this is likely due to a JVM optimization 
that can be disabled with -XX:-OmitStackTraceInFastThrow.
java.lang.ClassCastException: 

为什么要访问[:bu hu]而不是{:bu hu}?它似乎与嵌套的矢量很好,但扔了一张地图,jvm对我生气,呕吐难以理解的淫秽。

2 个答案:

答案 0 :(得分:4)

我得到了更好的堆栈跟踪:

visiting: :title
visiting: :bu
visiting: hu
visiting: [:bu hu]

ClassCastException clojure.lang.Keyword cannot be cast to java.util.Map$Entry  clojure.lang.ATransientMap.conj (ATransientMap.java:44)

[:bu hu]不是地图,而是地图中的第一个MapEntry。不幸的是,它实际上并不是clojure.lang.MapEntry的实例。在您传递到walk的函数被应用之前,postwalk会将其变为向量(postwalk在内部调用walk。即使在reading the code之后我仍然难以相信。

我不确定这是最好的方法。但我认为至少要知道为什么会发生这种情况对你有帮助。

答案 1 :(得分:1)

[:bu" hu"]是一个clojure.lang.MapEntry,postwalk将访问地图中的每个条目。可悲的是,clojure.walk / postwalk将MapEntry作为clojure.lang.PeristentVector传递,因此无法在postwalk中可靠地区分条目和向量。我想你需要使用你自己的步行实现。