大多数嵌入式列表采用Clojure形式

时间:2017-12-27 17:34:21

标签: 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))

我不是要求全面实施,但如果有人能给我一些指示,我将非常感激。

感谢。

2 个答案:

答案 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的相对新人。基于一些提示而不是遵循基于拉链的解决方案,您将获得更多自己做的事情。