我是Clojure的新手,我需要编写一个函数,在给定一些Clojure形式的情况下,用一些值替换最嵌套的列表。例如:
(my-fn '(+ [* a b] (* c d) (* e (/ f g))) 'foo)
=> (+ (* a b) (* c d) (* e foo))
(my-fn '(+ [* a b] (* c d) (* e foo)) 'bar)
=> (+ [* a b] bar (* e foo))
我不是要求全面实施,但如果有人能给我一些指示,我将非常感激。
感谢。
答案 0 :(得分:2)
有一种方法可以在clojure的核心库中一次执行此操作: zippers
关键是你可以在上下文中遍历和修改树。它看起来像这样:
(require '[clojure.zip :as z])
(defn replace-deepest [data replacer]
(->> data
z/seq-zip
(iterate z/next)
(take-while (complement z/end?))
(apply max-key #(if (seq? (z/node %))
(count (z/path %))
-1))
(#(z/replace % replacer))
z/root))
user> (replace-deepest '(+ [* a b] (* c d) (* e (/ f g))) :asd)
;;=> (+ [* a b] (* c d) (* e :asd))
user> (replace-deepest '(+ [* a b] (* c (+ x (* y z)) d) (* e (/ f g))) :asd)
;;=> (+ [* a b] (* c (+ x :asd) d) (* e (/ f g)))
此方法遍历集合深度优先收集数据,然后比较z/path
值计数(路径是上述上下文的一部分)。然后你可以替换节点(实际上用替换值重建树)
答案 1 :(得分:0)
至于知道最深的'是的,你需要首先解析所有表格才能找到这个答案,然后做一个已经知道这个的第二个解析。您可能需要每个解析的递归函数(因此有两个递归函数)。
您可以在所有表单上map/mapv
(取决于输入是vector
还是list
),对任何满足coll?
的任何表单进行递归,否则保留如果它不是“某种价值”,或者如果是的话就改变它,并且在最深处的那种情况下形成它。水平。
你还需要保持'状态'是否已经在最深层次进行了替换,因此不会发生重复替换。可以将状态保存为第二个解析递归函数的参数。您可能需要一个首次调用递归函数的初始函数。
请注意,coll?
对于地图数据结构返回true,因此您可能希望使用更精细的内容,例如(some-fn list? vector?)
或(every-pred coll? (complement map?))
。 seq?
无法为矢量工作。
这是几个指针而不是完整实现,适合Clojure的相对新人。基于一些提示而不是遵循基于拉链的解决方案,您将获得更多自己做的事情。