macros - 减少 "for"理解重复

标签 macros clojure code-duplication for-comprehension

在我对 Clojure For Comprehension example 的回答中,我想删除一些重复内容:

(def all-letters (map char (range 65 90)))
(defn kw [& args] (keyword (apply str args)))
(concat
  (for [l all-letters] (kw l))
  (for [l all-letters l2 all-letters] (kw l l2))
  (for [l all-letters l2 all-letters l3 all-letters] (kw l l2 l3)))

我想删除重复的“for”。我编写了以下宏:

(defmacro combine [times]
 (let [symbols (repeatedly times gensym)
       for-params (vec (interleave symbols (repeat 'all-letters)))]
    `(for ~for-params (kw ~@symbols))))

适用于:

 (concat (combine 1) (combine 2) (combine 3))

但是如果我尝试:

 (for [i (range 1 4)] (combine i))

我得到:

CompilerException java.lang.ClassCastException: clojure.lang.Symbol cannot be cast to java.lang.Number, compiling:(NO_SOURCE_PATH:177) 

这是怎么回事?有没有更好的方法来删除重复项?

最佳答案

您的问题是 combine 是一个在编译时扩展的宏。当您尝试扩展符号 i 时,它会失败,因为它被设计为采用数字(次)。 i 只是编译时的一个符号,它仅在运行时计算为数值。

我建议将 combine 重写为函数而不是宏:这里实际上并不需要宏,并且函数通常更方便(如本例所示!)。

这是一个递归组合,可能大致可以满足您的要求:

(defn combine
    ([times] (combine times nil))
    ([times letters]
      (if (<= times 0)
        (keyword (apply str letters))
        (flatten (for [l all-letters] (combine (dec times) (cons l letters)))))))

关于macros - 减少 "for"理解重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11532058/

相关文章:

c++ - 这个 C++ 宏有什么作用(竞争性编程)?

Clojure STM 歧义因子

c# - 在 C# 中删除代码重复

Java:相同的对象,如何避免重复的代码

c++ - 如何在不重复代码的情况下在子类中获取相同的方法代码?

macros - 什么时候在 Erlang 中使用宏函数?

c - Linux内核FIELD_SIZEOF宏解释

使用函数调用作为参数的 C 错误检查宏定义不会在 MSVC 上编译

java - 在 Leiningen 项目中 fork 一个 JVM

java - 将子进程输出直接通过管道传输到标准输出 (java/clojure)