Обход дерева векторов
Я хочу пройти через векторное дерево, которое представляет структуры данных сбоя:
[:div {:class "special"} [:btn-grp '("Hello" "Hi")]]
Затем я хочу отправить по ключевому слову вектора, если для ключевого слова был определен мультиметод, то он вернет другой набор векторов, который заменит исходный тег.
Например, приведенная выше структура будет преобразована в:
[:div {:class "special"} [:div [:button "Hello"] [:button "Hi"]]]
Пользовательский мультиметод получит список ("привет", "привет") в качестве параметров. Затем он вернет div, содержащий кнопки.
Как мне написать функцию, которая пересекает вектор и отправляет по ключевому слову все остальное в форме в качестве параметра, а затем заменяет текущую форму возвращенной формой?
1 ответ
Решение
(ns customtags
(:require [clojure.walk :as walk]))
(def customtags (atom {}))
(defn add-custom-tag [tag f]
(swap! customtags assoc tag f))
(defn try-transform [[tag & params :as coll]]
(if-let [f (get @customtags tag)]
(apply f params)
coll))
(defmacro defcustomtag [tag params & body]
`(add-custom-tag ~tag (fn ~params ~@body)))
(defn apply-custom-tags [coll]
(walk/prewalk
(fn [x]
(if (vector? x)
(try-transform x)
x)) coll))
Используй это:
(require '[customtags :as ct])
(ct/defcustomtag :btn-grp [& coll] (into [:div] (map (fn [x] [:button x]) coll)))
(ct/defcustomtag :button [name] [:input {:type "button" :id name}])
(def data [:div {:class "special"} [:btn-grp "Hello" "Hi"]])
(ct/apply-custom-tags data)
[:div {:class "special"} [:div [:input {:type "button", :id "Hello"}] [:input {:type "button", :id "Hi"}]]]