大多数嵌入式列表中的clojure形式



我对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?对向量不起作用。

那是很少的指针,而不是完整实现,适用于相对的新人。您会根据一些提示自己做更多的事情,而不是遵循基于拉链的解决方案。

最新更新