编写宏来交换两个符号的值

时间:2014-05-12 20:57:57

标签: macros clojure

我无法想到任何可能的用例,但作为一种练习,试图围绕Clojure的宏进一步思考,我正在尝试编写一个宏来交换分配给两个符号的值。 / p>

我尝试了两件事:

方法1:

(defmacro swap [x y]
  `(let [tmp# ~x]
     (def x ~y)
     (def y ~tmp#)))

方法2:

(defmacro swap [x y]
  `(let [tmp# ~x]
     (alter-var-root #'x (fn [] ~y))
     (alter-var-root #'y (fn [] ~tmp#))))

以下是我用来测试它的代码:

(def four 4)
(def five 5)

(swap four five)

(printf "four: %d\nfive: %d" four five)

预期产出:

four: 5
five: 4

但是,使用任一版本的宏,我得到java.lang.RuntimeException: Unable to resolve symbol: tmp# in this context。我使用auto gensym不正确吗?

使用方法1,我可以通过将最后一行更改为(def y tmp#)))(在~之前取出tmp#)来运行它,但是我得到了输出{{ 1}}没有交换。

1 个答案:

答案 0 :(得分:3)

忽略像这样改变vars的事实是一个坏主意,让我们假设你真的想要这样做。你的问题有两个方面:

  • 您在~tmp#上有一个取消引用,只需要tmp#
  • 您错过xy上的取消引用:您想要(def ~x ~y)(def ~y tmp#)

您编写的版本始终会分配给名为xy的变种,而不是修改用户提供的变量。