我对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))
我不是要全面实施,但是如果有人可以给我一些指示,我会非常感谢。
谢谢。
有一种方法可以在Clojure的Core Library中的一个通过中执行此操作:拉链
关键是您可以在上下文中穿越并修改树。看起来像这样:
(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
值计数(路径是上述上下文的一部分)。然后,您可以替换节点(实际上用更换值重建树)
就知道'最大深度'是什么,您需要首先要仔细研究所有形式,以找到这个答案,然后进行第二个已经知道这一点的解析。您可能需要每个分析的递归功能(因此两个递归功能)。
您可以在所有表格上 map/mapv
(取决于输入是 vector
还是 list
),为任何满足coll?
的任何表格递归,否则将表单保留,就像它不是"某个值"或更改它的情况如果是,并且处于"最深"级别。
您还需要保持在"状态"中是否已经在最深层次上进行的替换,以免重复替换。状态可以作为 second Parse 递归函数的参数保存。您可能需要一个初始功能,该功能首次调用递归功能。
请注意,coll?
对于地图数据结构返回true,因此您可能需要使用更精细的东西,例如(some-fn list? vector?)
或(every-pred coll? (complement map?))
。seq?
对向量不起作用。
那是很少的指针,而不是完整实现,适用于相对的新人。您会根据一些提示自己做更多的事情,而不是遵循基于拉链的解决方案。