Clojure:带有绑定映射的评估函数



我正在尝试编写一个函数eval-with-bindmap它接受两个参数,一个要评估的表达式和一个符号到值的映射,这些值将在评估中充当绑定。我不能使用let因为绑定可以在映射中按任何顺序排列(它应该同时适用于数组映射和哈希映射(,并且它还可能包含相互递归的函数绑定(如letfn(。例如:

(eval-with-bindmap '(+ a b) '{a (+ 1 b) b 2}) => 5

关于如何处理这个问题的任何提示都会很棒,谢谢。

一些简单的递归处理可以工作(除非你的表单扩展真的很深,否则你应该考虑尾递归版本(

(defn eval-with-bindings [form bind]
  (cond (seq? form) (apply (resolve (first form))
                           (map #(eval-with-bindings % bind) (rest form)))
        (and (symbol? form) (contains? bind form)) (eval-with-bindings (bind form) bind)
        :else form))
user> (eval-with-bindings '(+ a b) '{a (+ 1 b) b 2})
5

在无限循环 deps 的情况下,它只会与堆栈溢出一起下降:

user> (eval-with-bindings '(+ a b) '{a (+ 1 a) b 2})
StackOverflowError   clojure.lang.AFn.applyToHelper (AFn.java:148)
我想

说,更好的方法仍然是在let中使用eval,但以关心正确顺序的特殊方式将绑定映射处理成let向量。

例如,假设您有一个地图{a (+ 1 b) b 2}。对于每个键/表达式对,请检查表达式是否包含任何字母数字符号。b将是我们的候选人。在这种情况下,您将b 2移动到a (+ 1 b)之前,依此类推。

是的,正确的算法可能有点复杂,但是您不会在进一步eval时遇到任何麻烦。

最新更新