我想在数据结构中预先存储一堆函数调用,然后在另一个函数中评估/执行它们。
这对于使用defn
在命名空间级别定义的函数按计划工作(即使函数定义在我创建数据结构之后),但不适用于let [name (fn
或{{定义的函数1}}在函数内部。
这是我自己的小例子:
letfn
如果您对我的测试设置感到疑惑,要查看这6个语句的结果,我会评论/取消注释OK /失败行的具体内容,然后从REPL中调用(def todoA '(funcA))
(def todoB '(funcB))
(def todoC '(funcC))
(def todoD '(funcD)) ; unused
(defn funcA [] (println "hello funcA!"))
(declare funcB funcC)
(defn runit []
(let [funcB (fn [] (println "hello funcB"))]
(letfn [(funcC [] (println "hello funcC!"))]
(funcA) ; OK
(eval todoA) ; OK
(funcB) ; OK
(eval todoB) ; "Unable to resolve symbol: funcB in this context" at line 2
(funcC) ; OK
(eval todoC) ; "Unable to resolve symbol: funcC in this context" at line 3
)))
。
是否有一个简单的修复方法可以让(runit)
'd eval
d调用函数来为另一个函数中定义的函数工作?
更新
这(基于danlei的建议) 工作。让我们看看我是否可以在“现实生活中”使用这种方法。
quote
更新
此代码将进入我的Constraint Satisfaction Problem解决方案 - 我想找出who owns the zebra!我对Clojure很熟悉,尤其是函数式编程,这使得练习非常具有挑战性。我陷入了很多陷阱,但我很乐意,因为这是学习经历的一部分。
我曾经将约束指定为一堆简单的向量,如下所示:
(def todoB '(funcB))
(declare funcB)
(defn runit []
(binding [funcB (fn [] (println "hello funcB"))]
(funcB)
(eval todoB) ; "Unable to resolve symbol: funcB in this context" at line 1!
))
其中每个向量的第一个将指定约束的类型。但这导致我对这些规则的调度机制的笨拙实现,所以我决定将它们编码为(引用)函数调用:
[:con-eq :spain :dog]
[:abs-pos :norway 1]
[:con-eq :kools :yellow]
[:next-to :chesterfields :fox]
所以我可以用简单的'(coloc :japan :parliament) ; 10
'(coloc :coffee :green) ; 12
'(next-to :chesterfield :fox) ; 5
发送约束规则。这似乎更优雅和“lisp-y”。但是,这些函数中的每一个都需要访问我的域数据(名为eval
),并且这些数据会随着程序的运行而不断变化。我不想通过引入额外的参数来玷污我的规则,因此我希望vars
通过动态范围可用于vars
'd函数。
我现在已经了解到动态范围可以使用eval
完成,但它也需要binding
。
答案 0 :(得分:5)
你的意思是这样吗?
(def foo '(bar))
(declare bar)
(binding [bar (fn [] (println "hello bar"))]
(eval foo))
如果是,您的问题将减少到:
(let [foo 1]
(eval 'foo))
这不起作用,因为eval不会在词汇环境中进行评估。你可以使用vars解决这个问题:
(declare foo)
(binding [foo 1]
(eval 'foo))
就这一点而言,Clojure似乎与CL具有相似的语义,参见CLHS:
评估当前动态环境和null词法环境中的表单。
答案 1 :(得分:3)
我认为你正在解决错误的问题。在函数式语言中,函数是值,并且可以分配给可以存储任何其他值的任何值,例如,一张地图。你不应该试图操纵命名空间或评估任何东西 - 这不是perl。
尝试这样的操作,并使用assoc在本地更改地图:
user=> (def fnmap {:funcA (fn [x] (inc x)), :funcB (fn [x] (* x 2))})
#'user/fnmap
user=> ((:funcA fnmap) 10)
11
user=> ((:funcB fnmap) 10)
20