gpt4 book ai didi

clojure - 在 Clojure 字符串中执行函数?

转载 作者:行者123 更新时间:2023-12-05 03:45:56 25 4
gpt4 key购买 nike

我正在处理一个静态站点生成器项目,有一次我得到了一个我可以操作的站点的字符串表示形式(打嗝格式)。我将该字符串转换为 map :

(clojure.edn/read-string page)

此时我的页面将如下所示:

{ :header {
:title "Index"
:meta-desc "Indx Page"}
:page [:div.Page.Home
!!+Do-Math+!! ; This is the core of the question
[:p (do-math 2 2)] ; This is also an option to replace the above line
[:div.Home-primary-image-wrapper]
;More HTML stuff here
]
}

然后,如上面两行所述,目标是允许在稍后呈现 html 之前执行特定代码。

我的第一个想法是嵌入特定的字符串,然后将其替换为函数值:

(defn do-math []
(str [:p (+ 2 2)]))

(clojure.edn/read-string (clojure.string/replace page "!!+Do-Math+!!" (do-math)))

我遇到的问题是我希望能够将值嵌入到字符串中以执行更有用的操作。

我想完成的一个非工作示例

我们有这个字符串 !!+Do-Math 2 2++!! 然后它会转到上面函数的修改版本,需要两个参数:

(defn do-math [val val2]
(str [:p (+ val val2)]))

我遇到的问题是我不确定如何可靠地替换这样的字符串,我也无法将被替换的字符串值传递到执行替换的函数中。我不确定这条路线是否可行。

另一种选择是在渲染 html 之前直接执行返回的 map 中的函数。在上面的示例中,我有:

[:p (do-math 2 2)]

这会给我相同的结果。是否可以查看 map/vector 并找到这些函数调用的实例并在当前命名空间中执行它们,如果是这样,那是不是比上面的字符串替换方法更好的选择?

最佳答案

我会定义一个特殊的语法,用于可以评估的事物,然后使用 postwalk 遍历树。例如,您可以决定要计算的所有内容都是一个以命名空间关键字 ::eval 开头的向量。例如,您可以拥有以下数据:

(def test-data
[:div.Page.Home
[:p [::eval
:add
[::eval :mul 3 3]
[::eval :mul 4 4]]]
[:div.Home-primary-image-wrapper]])

满足这个谓词的树节点被称为可以被评估的节点:

(defn evaluable? [x]
(and (vector? x)
(= ::eval (first x))))

下面是遍历树并对要评估的节点求值的函数:

(defn evaluate-tree-nodes [tree evaluator-fn]
(clojure.walk/postwalk
#(if (evaluable? %)
(apply evaluator-fn (rest %))
%)
tree))

这是一个评估函数,您可以根据自己的喜好定义它来执行评估。例如,您可以决定只支持两个操作,:mul:add:

(defn my-evaluator [f & args]
(case f
:add (apply + args)
:mul (apply * args)))

你会像这样使用它:

(evaluate-tree-nodes test-data my-evaluator)
;; => [:div.Page.Home [:p 25] [:div.Home-primary-image-wrapper]]

的确,您可以做一些更奇特的事情,并尝试将表达式中的符号映射到当前命名空间中定义的函数,但如果不小心,您可能最终会重新实现 Lisp。它也可能引入其他复杂性。上面的解决方案只是您可以做什么的一个提示,您可以扩展它。

关于clojure - 在 Clojure 字符串中执行函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65569647/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com