我正在尝试编写一个函数eval-with-bindmap
,它接受两个参数,一个要评估的表达式和一个符号映射到值,这些值将作为评估中的绑定。我不能使用let
,因为绑定可能是地图中的任何顺序(它应该同时适用于数组映射和散列映射),它也可能包含相互递归的函数绑定(如{{ 1}})。例如:
letfn
关于如何处理此问题的任何提示都很棒,谢谢。
答案 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
的麻烦。