我正在研究一个使用parsley解析其语法的clojure重构库。 我将欧芹升级到0.9.1,然后一个函数失败。
这是该功能的作用:
假设我们有"(defn a [b] (:foo b))"
,重构工具将解析争论和地图查找:[b]
和(:foo b)
。然后将(:foo b)
转换为地图:{b (foo :foo)}
并将b
中的符号[b]
替换为地图的值(foo :foo)
。我终于得到了{(foo :foo)}
。
以下代码用于最后一步:
clojure.walk/postwalk-replace {#net.cgrand.parsley.Node{:tag :atom, :content ["b"]} #net.cgrand.parsley.Node{:tag :map, :content ["{" #net.cgrand.parsley.Node{:tag :atom, :content ["foo"]} #net.cgrand.parsley.Node{:tag :whitespace, :content [" "]} #net.cgrand.parsley.Node{:tag :atom, :content [":foo"]} #net.cgrand.parsley.Node{:tag :whitespace, :content [" "]} "}"]}}
#net.cgrand.parsley.Node{:tag :vector, :content ["[" #net.cgrand.parsley.Node{:tag :atom, :content ["b"]} "]"]}
报告:`UnsupportedOperationException无法创建空:net.cgrand.parsley.Node net.cgrand.parsley.Node(parsley.clj:19)
然而,当我打印{#net.cgrand.parsley.Node{:tag :atom, :content ["b"]} #net.cgrand.parsley.Node{:tag :map, :content ["{" #net.cgrand.parsley.Node{:tag :atom, :content ["foo"]} #net.cgrand.parsley.Node{:tag :whitespace, :content [" "]} #net.cgrand.parsley.Node{:tag :atom, :content [":foo"]} #net.cgrand.parsley.Node{:tag :whitespace, :content [" "]} "}"]}}
和
#net.cgrand.parsley.Node{:tag :vector, :content ["[" #net.cgrand.parsley.Node{:tag :atom, :content ["b"]} "]"]}
然后将它们传递给postwalk:
(clojure.walk/postwalk-replace {{:tag :atom, :content ["b"]}
{:tag :map,
:content
["{"
{:tag :atom, :content ["foo"]}
{:tag :whitespace, :content [" "]}
{:tag :atom, :content [":foo"]}
{:tag :whitespace, :content [" "]}
"}"]}}
{:tag :vector, :content ["[" {:tag :atom, :content ["b"]} "]"]})
Everythins很好,我得到了我想要的{:content
["["
{:content
["{"
{:content ["foo"], :tag :atom}
{:content [" "], :tag :whitespace}
{:content [":foo"], :tag :atom}
{:content [" "], :tag :whitespace}
"}"],
:tag :map}
"]"],
:tag :vector}
我的问题是:#net.cgrand.parsley.Node
在欧芹中意味着什么?为什么我删除这些符号后(使用pprint)问题就消失了。
答案 0 :(得分:2)
问题是Parsley的节点是记录,而不是常规地图。 #net.cgrand.parsley.Node{...}
是此记录类型的文字表示法。记录无法清空(与clojure.core/empty
一样),clojure.walk
函数依赖于使用empty
清空集合,因此clojure.walk
函数无法对记录进行操作。
恰好pprint
在打印记录时省略了标记 - 它只是将它们打印为常规地图 - 所以如果你回读pprint
ed表示,你会得到一张地图,然后可以将其清空,以便将其传递给postwalk
。
正确的行动方案取决于您希望完成的具体内容。如果你想要实际的Node
个实例,你需要编写自己的树步行者(也许适应clojure.walk/walk
);如果你对常规地图没问题,你可以编写一个非常简单的树步行者用Parsley输出中的地图替换Node
s,然后在变换后的树上使用clojure.walk
。