clojure宏中符号求值的正确方法
我有一个文件,其中包含一些可信的clojure源代码:clojure宏中符号求值的正确方法,clojure,macros,Clojure,Macros,我有一个文件,其中包含一些可信的clojure源代码: ((+ab)(*ab)(-ab)) 对于列表中的每个项目,我要生成一个匿名函数: (fn[ab](+ab)) (fn[ab](*ab)) (fn[ab](-ab)) 如果我打电话给下面的马可 (定义宏创建fn [args exprs] `(fn~args~exprs)) 直接使用一些clojure代码,它可以完美地工作: user=>(宏扩展-1'(创建fn[ab](*ab))) (clojure.core/fn[ab](*ab))
((+ab)(*ab)(-ab))
对于列表中的每个项目,我要生成一个匿名函数:
(fn[ab](+ab))
(fn[ab](*ab))
(fn[ab](-ab))
如果我打电话给下面的马可
(定义宏创建fn
[args exprs]
`(fn~args~exprs))
直接使用一些clojure代码,它可以完美地工作:
user=>(宏扩展-1'(创建fn[ab](*ab)))
(clojure.core/fn[ab](*ab))
但是,当我将文件的上下文绑定到本地并尝试映射宏时,它将不起作用。在访问第一个生成的函数时,我收到错误消息“java.lang.RuntimeException:无法解析此上下文中的符号:a”
(请注意,我必须在宏中添加一个额外的eval
,以获取map使用的匿名函数中使用的符号e
的值)
(定义宏创建fn
[args exprs]
`(让[e#(eval~exprs)]
(fn~args)
e#))
(让[exprs(读取字符串)(+ab)(*ab)(-ab)))
fns(地图
(fn[e](创建fn[a b]e))
exprs)]
(第一次)
非常感谢您的帮助 让我们看看宏扩展后的整个代码。此代码:
(let [exprs (read-string "((+ a b) (* a b) (- a b))")
fns (map
(fn [e] (create-fn [a b] e))
exprs)]
(first fns))
扩展到此,其中e_uu900_u_u自动_uu
是由e#
生成的符号:
为什么这样不行?一个原因是a
和b
甚至不在(eval e)
的范围之内。下一步您可能会尝试以下方法:
(defmacro create-fn [args exprs] `(fn ~args (eval ~exprs)))
展开后,生成的函数如下所示:
(let [exprs (read-string "((+ a b) (* a b) (- a b))")
fns (map
(fn [e] (fn [a b] (eval e)))
exprs)]
(first fns))
(map
(fn [e] (eval (concat '(fn [a b]) (list e))))
exprs)
这看起来不错,但因为eval
在一个空的词汇环境中求值。换句话说,eval
即使使用此代码也不会看到a
和b
您可以放弃宏,只需手动将代码转换为可以评估的内容,如下所示:
(let [exprs (read-string "((+ a b) (* a b) (- a b))")
fns (map
(fn [e] (fn [a b] (eval e)))
exprs)]
(first fns))
(map
(fn [e] (eval (concat '(fn [a b]) (list e))))
exprs)
或者,您可以将变量a
和b
声明为动态变量,然后在计算表达式之前使用binding
进行设置
(declare ^:dynamic a ^:dynamic b)
(let [exprs (read-string "((+ a b) (* a b) (- a b))")
fns (map
(fn [e] (fn [a1 b1] (binding [a a1 b b1] (eval e))))
exprs)]
(first fns))
如果您不想在名称空间中包含a
和b
,则可以设置另一个名称空间和
我建议的解决方案不使用宏。它们在这里没有用处,因为宏是在编译时展开的,而表达式是在运行时读取的。如果你真的想在这里使用宏,你需要移动
读取字符串
,文件处理代码在defmacro
中exprs
绑定到(+ab)
,你调用eval
,如果我在宏create fn
中放入(println exprs)
,错误会被纠正,它会打印“e”。我的理解是,在宏扩展期间,exprs
绑定到符号e
,而不是它的值。因此,我想我需要在exprs
上调用eval
,以获得符号e
的值……非常感谢您的详细回答!这有助于我在宏观评估期间理解词汇范围。令人伤心的是,我将使用非宏解决方案,因为它看起来更容易:-)