Clojure:具有绑定映射的Eval函数

时间:2018-01-16 14:01:40

标签: clojure

我正在尝试编写一个函数eval-with-bindmap,它接受​​两个参数,一个要评估的表达式和一个符号映射到值,这些值将作为评估中的绑定。我不能使用let,因为绑定可能是地图中的任何顺序(它应该同时适用于数组映射和散列映射),它也可能包含相互递归的函数绑定(如{{ 1}})。例如:

letfn

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

2 个答案:

答案 0 :(得分:1)

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

(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的情况下,它会随着stackoverflow而下降:

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

答案 1 :(得分:1)

我说,更好的方法仍然是在eval内使用let,但是以一种特殊的方式处理你的绑定地图到let向量适当的顺序。

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

是的,正确的算法可能有点复杂,但是后来你不会再遇到eval的麻烦。