mep*_*ide 5 macros clojure partial
这类似于在处理Clojure宏中讨论的问题作为一个函数,但是当在顶部答案中尝试该方法时,我得到了一个错误.希望有太多关于我的特定应用程序的信息是没有必要的,因为它非常复杂,但这是我尝试做的事情的简化版本:
(defmacro make-fn [m arg1]
`(fn [& args#]
(eval `(~'~m ~'~arg1 ~@args#))))
Run Code Online (Sandbox Code Playgroud)
我在这个上下文中使用了宏:
(let [columns (make-columns table-width)
table-name (keyword (str "table_" n))]
(apply (make-fn helpers/tbl table-name) columns))
Run Code Online (Sandbox Code Playgroud)
"helpers/tbl"是一个宏,它需要一个表名关键字和一个包含列规范的可变数量的列表(如[:varchar 100]或其他东西).我正在尝试动态创建随机数据库表规范,以方便一些测试.无论如何,当试图执行上面的代码时,我收到以下错误:
CompilerException java.lang.RuntimeException: Unable to resolve symbol: table-name in this context, compiling:(NO_SOURCE_PATH:1)
Run Code Online (Sandbox Code Playgroud)
我有点理解这个问题:宏扩展是在编译时完成的,我试图在宏扩展中包含一个运行时值,因此奇怪的使用引用和取消引用来使所有内容都设置得恰到好处.我基本上想要部分用于宏,并且我需要能够将这种机制重用于不同命名空间中的不同宏,并且所有的变量分辨率都是正确的.这甚至可能吗?
该问题是由 Clojure 解析语法引用(反引号)表达式中的符号的方式引起的。为了避免无意的变量捕获,Clojure 始终将语法引用表达式中的符号解释为引用 Var(而不是局部变量)。
您可以通过“滚动自己的”表单构建代码来解决这个问题,相当于语法引用生成的代码。这就像罪恶一样丑陋,但它有效......只是不要说我没有警告过你:
(defmacro make-fn [m arg1]
(let [g (gensym)]
(list 'fn ['& g]
(list 'eval (list 'concat (list 'list m arg1) g)))))
Run Code Online (Sandbox Code Playgroud)
哇,这就像我的 Common Lisp 岁月的闪回……