5
说我想要做的Clojure宏,执行以下操作:与符号解析正确处理在宏
If x is a list calling the function "bar"
return :foobar
else
return x as a string
但是,没有定义bar
;相反,它只是在内部宏观使用,就像这样:
(foo (bar))
:foobar
(foo 1)
"1"
有人会做这样的事情:
(defmacro foo [x]
(if (and (coll? x) (= (first x) 'bar))
:foobar
(str x)))
这个伟大的工程为(bar)
情况,以及为文字。然而,符号不工作打算,给予而不是它的关联值的符号名称:
user=> (def y 2)
#'user/y
user=> (foo y)
"y"
人们可以将它传递给str
之前呼吁x
的eval
功能,但是这会导致let
使用该功能时问题:
user=> (let [a 3 b (foo a)] b)
java.lang.UnsupportedOperationException: Can't eval locals (NO_SOURCE_FILE:89)
据推测,问题与符号解析做,所以也许我们想个办法解决了与语法的报价:
(defmacro foo [x]
`(if (and (coll? '~x) (= (first '~x) '~'bar))
:foobar
(str ~x)))
现在,问题在于(foo (bar))
,因为这会将else子句展开为(clojure.core/str (bar))
,这会引发异常,因为bar
未定义。然后,我尝试做一些恶作剧与eval
:
(defmacro foo [x]
`(if (and (coll? '~x) (= (first '~x) '~'bar))
:foobar
(eval '(str ~x))))
但是这不符合再次let
绑定工作:
user=> (let [a 1 b (foo a)] b)
java.lang.Exception: Unable to resolve symbol: a in this context (NO_SOURCE_FILE:153)
所以我不知所措我真的在这里。似乎修复一个问题打破了另一个问题。有没有使这个宏,使得它在下列情况下,更好的,更简单的方法:
- 在
let
绑定 - 随着
(bar)
- 的符号
附:如果有人很好奇为什么我想这样做,我正在为Yahoo的YQL服务开发一个DSL,我希望能够做到像(select (table :t) ...)
这样的事情,但我需要能够传递符号,如以及文字。
我想我没有考虑语法引用只是表达式的一部分,但似乎这样做。谢谢! – Scott