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