Именно поэтому я впервые создал библиотеку Tupelo Forest.
Пожалуйста, смотрите доклад Clojure Conj 2017 .
Я начал некоторые документы здесь .Вы также можете увидеть живых примеров здесь .
Обновление
Вот как вы можете использовать библиотеку Tupelo Forest для этого:
Сначала определите данные в дереве абстрактного синтаксиса (AST), используя формат Hiccup:
(with-forest (new-forest)
(let [data-hiccup [:rpc
[:fn {:type :+}
[:value 2]
[:value 3]]]
root-hid (add-tree-hiccup data-hiccup)
с результатом:
(hid->bush root-hid) =>
[{:tag :rpc}
[{:type :+, :tag :fn}
[{:tag :value, :value 2}]
[{:tag :value, :value 3}]]]
Покажите, как walk-tree
работает с использованием "перехватчика отображения"
disp-interceptor {:leave (fn [path]
(let [curr-hid (xlast path)
curr-node (hid->node curr-hid)]
(spyx curr-node)))}
>> (do
(println "Display walk-tree processing:")
(walk-tree root-hid disp-interceptor))
с результатом:
Display walk-tree processing:
curr-node => {:tupelo.forest/khids [], :tag :value, :value 2}
curr-node => {:tupelo.forest/khids [], :tag :value, :value 3}
curr-node => {:tupelo.forest/khids [1037 1038], :type :+, :tag :fn}
curr-node => {:tupelo.forest/khids [1039], :tag :rpc}
, затем определите операторы и перехватчик для преобразования поддерева, например (+ 2 3)
=> 5
op->fn {:+ +
:* *}
math-interceptor {:leave (fn [path]
(let [curr-hid (xlast path)
curr-node (hid->node curr-hid)
curr-tag (grab :tag curr-node)]
(when (= :fn curr-tag)
(let [curr-op (grab :type curr-node)
curr-fn (grab curr-op op->fn)
kid-hids (hid->kids curr-hid)
kid-values (mapv hid->value kid-hids)
result-val (apply curr-fn kid-values)]
(set-node curr-hid {:tag :value :value result-val} [])))))}
] ; end of let form
; imperative step replaces old nodes with result of math op
(walk-tree root-hid math-interceptor)
Затем мы можем отобразитьмодифицированное дерево AST, которое содержит результат (+ 2 3)
:
(hid->bush root-hid) =>
[{:tag :rpc}
[{:tag :value, :value 5}]]
Вы можете увидеть живой код здесь .