【发布时间】:2011-02-04 05:44:04
【问题描述】:
我想在一个数据结构中预先存储一堆函数调用,然后在另一个函数中评估/执行它们。
这对于使用defn 在命名空间级别定义的函数按计划工作(即使函数定义是在我创建数据结构之后出现的),但不适用于函数内部由let [name (fn 或letfn 定义的函数.
这是我的小型独立示例:
(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
)))
如果您想知道我的测试设置,请查看这 6 条语句的结果,我注释/取消注释特定于 OK/failing 行,然后从 REPL 调用 (runit)。
我可以采取一个简单的修复方法来让eval'd quoted 调用函数来为另一个函数中定义的函数工作吗?
更新:
这(基于 danlei 的建议)确实有效。让我们看看我能否让这种方法在“现实生活”中发挥作用!
(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!
))
更新:
此代码将进入我的Constraint Satisfaction Problem 解决方案 - 我想找出who owns the zebra!我对 Clojure 非常陌生,尤其是函数式编程,这使得练习变得非常具有挑战性。我掉进了很多坑,但我可以接受,因为这是学习体验的一部分。
我曾经将约束指定为一堆简单的向量,如下所示:
[: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
所以我可以使用简单的eval 发送约束规则。这似乎更加优雅和“lisp-y”。但是,这些函数中的每一个都需要访问我的域数据(名为vars),并且这些数据会随着程序的运行而不断变化。我不想通过引入额外的参数来破坏我的规则,所以我希望 vars 通过动态作用域对 eval'd 函数可用。
我现在了解到可以使用 binding 完成动态范围,但它还需要 declare。
【问题讨论】:
-
您是在努力解决问题还是真的在尝试实现某些东西?如果是后者,我想知道你试图做什么,迫使你使用这样的设计——乍一看延迟或普通的闭包可以解决问题。
-
@cgrand:感谢您的关注!我添加了第二个更新来解释我想要做什么。这同时对我有用,但我当然愿意接受更好的建议!
-
@cgrand:我的帖子Constraint Satisfaction Problem 现在有了我的完整解决方案。如果你有兴趣,你可以在那里看到
binding。对于我的业余方法,我非常愿意接受建设性的批评。