【问题标题】:Reducing "for" comprehension duplication减少“for”理解重复
【发布时间】:2012-07-17 23:04:17
【问题描述】:

在我对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) 

发生了什么事?有没有更好的去除重复的方法?

【问题讨论】:

    标签: macros clojure code-duplication for-comprehension


    【解决方案1】:

    您的问题是 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)))))))
    

    【讨论】:

    • 是因为“for”也是宏吗?
    • for 不是导致问题的原因,它是一个宏,但它具有您在运行时所期望的效果 - 真正的问题是 i,它是编译时的符号在combine 宏中使用的时间。添加了更多解释性说明。
    【解决方案2】:

    您可以修改宏,使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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-20
      • 2015-06-21
      • 1970-01-01
      • 1970-01-01
      • 2015-06-28
      • 2021-07-19
      • 2011-06-13
      相关资源
      最近更新 更多