使用这些数据
(def html
'(html (head (title "the fortune cookie institute"))
(body
(h1 "Welcome to the Fortune Cookie Institute")
(p "Our fortunes are guaranteed accurate no matter what.")
(br)
(div (p "Like these"))
(ol
(li "You will gain weight")
(li "Taxes will rise")
(li "Fusion power will always be 50 years away"))
(br)
(p "Submit your own fortunes to [email protected]!"))))
选项1:使用内置的clojure walk
(require '[clojure.walk :refer [prewalk]])
(prewalk (fn [x] (if (= x 'p) 'h2 x)) html)
注意,行者继续行走,会在列表头部之外的“p”处找到位置(这不是期望的)。
选项2:使用specter
(require '[com.rpl.specter :refer [ALL FIRST setval recursive-path]] )
(setval [ALL (recursive-path [] RECURSE
(cond-path
[sequential? FIRST (pred= 'p)] FIRST
sequential? [ALL RECURSE]))]
'h2
html)
这里的specter只寻找列表头部的“p”(使用sequential?而不是list?,因为你的结构非常接近hiccup,它将使用向量。sequential适用于列表和向量。)
选项3
(defn shout [html]
(if-not (sequential? html)
html
(if (= 'p (first html))
(cons 'h2 (->> (rest html)
(map shout)))
(map shout html))))
我认为这真正实现了递归和消耗栈,但HTML的深度并不足以让它成为问题。我不确定是否存在一个更好的loop [h html] ... (recur ...
答案。