【问题标题】:Clojure macros and quotesClojure 宏和引号
【发布时间】:2013-02-14 21:53:12
【问题描述】:

我正在尝试“获取”clojure 宏,并根据现有的 are 宏编写一个调整版本的 are 宏。 我想要的调整是签名[argv expr args] 而不是[argv expr & args] 所以我试过了

(defmacro are2 [argv expr args] `(clojure.test/are ~arg ~expr ~@args))

哪种有效,除了它需要一个不带引号的列表:

(are2 [input] (= 0 input) (1 2 3))

我宁愿它期望一个引用列表:

(are2 [input] (= 0 input) '(1 2 3))

但这会导致:

Unable to resolve symbol: quote in this context.

如果我尝试

(are2 [input] (= 0 input) (list 1 2 3))

然后list 本身被作为测试用例处理。

我有什么不明白/我怎样才能超越我的宏中的引用

【问题讨论】:

  • 可以在宏展开后显示表单示例吗?最后你想从(are2 [input] (= 0 input) (1 2 3))得到什么?
  • 我希望它'做 clojure.test/are 所做的任何事情,但 sig 中没有 & ;-) 这是 clojure.test/are 的代码:(defmacro are [argv expr & args ] (if (or (and (empty?argv) (empty?args)) ;; 捕获错误数量的 args (and (pos? (count argv)) (pos? (count args)) (zero? (mod (count args) (count argv))))) `(temp/do-template ~argv (is ~expr) ~@args) (throw (IllegalArgumentException. "The number of args doesn't match are's argv."))))
  • 但我想了解的是,为什么我的重用尝试失败了
  • 还有一个问题。为什么需要将引用列表传递给宏?
  • 我“不需要”——我想了解它为什么不起作用。引用是传递文字列表的常用方法吗?而传递像 (1 2 3) 这样的未引用列表通常会得到一个 Long 不能被强制转换为 IFn

标签: clojure


【解决方案1】:

'(1 2 3) 正在扩展为 (quote (1 2 3)),其中有一个额外的 quote 符号和一个太多级别的列表,您可以使用 macroexpand-1 看到:

user> (macroexpand-1 '(are2 [input] (= 0 input) '(1 2 3)))
(clojure.test/are [input] (= 0 input) quote (1 2 3)) 

您可以通过将其包装成 int 并休息来从列表中删除报价

 user> (defmacro are2 [argv expr args] 
          `(clojure.test/are ~argv ~expr ~@(first (rest args))))
#'user/are2
user> (macroexpand-1 '(are2 [input] (= 0 input) '(1 2 3)))
(clojure.test/are [input] (= 0 input) 1 2 3) 

然后作为测试运行:

user> (are2 [input] (= 0 input) '(1 2 3)

FAIL in clojure.lang.PersistentList$EmptyList@1 (NO_SOURCE_FILE:1)
expected: (= 0 1)
  actual: (not (= 0 1))

FAIL in clojure.lang.PersistentList$EmptyList@1 (NO_SOURCE_FILE:1)
expected: (= 0 2)
  actual: (not (= 0 2))

FAIL in clojure.lang.PersistentList$EmptyList@1 (NO_SOURCE_FILE:1)
expected: (= 0 3)
  actual: (not (= 0 3))
false 

【讨论】:

  • 这是解决问题的常用方法吗?还是我的问题本身有些特殊?事实上,(first (rest)) 不等于 (eval ...) 吗?
  • 就“惯用”而言,我认为您的宏很好。如果您想要使用带引号的列表的语法,这就是宏的用途,那么您将拥有更多的权力。 (first(rest ..)) 与 (eval 不同之处在于它不会启动编译器并且它会删除一层嵌套。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-05
相关资源
最近更新 更多