Macros 减少;至于;理解重复
在我对的答复中,我想消除一些重复:Macros 减少;至于;理解重复,macros,clojure,code-duplication,for-comprehension,Macros,Clojure,Code Duplication,For Comprehension,在我对的答复中,我想消除一些重复: (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
(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)))))))
(defn联合收割机
([次数](合并次数为零))
([泰晤士报]
(如果(您可以修改宏,使concat
成为宏的一部分,如下所示。但我同意Mikera的观点,最好有一个函数
(defmacro combine [start end]
`(concat
~@(for [i (range start end)]
(let [symbols (repeatedly i gensym)
for-params (vec (interleave symbols (repeat 'all-letters)))]
`(for ~for-params (kw ~@symbols))))))
user=> (combine 1 2)
(:A :B :C :D :E :F :G :H :I :J :K :L :M :N :O :P :Q :R :S :T :U :V :W :X :Y)
这是因为“for”也是一个宏吗?for
不是导致问题的原因,它是一个宏,但它在运行时会产生预期的效果-真正的问题是i
,它是编译时在combine
宏中使用的一个符号。添加了一些解释性说明。