是否可以为多签名函数中的所有实现设置公共绑定?

时间:2010-12-03 18:12:29

标签: clojure

(这是一个关于风格的问题。我知道这可以用一堆条件,多方法等来完成。)

在以下函数中,每个实现都定义了null-vector。如何为整个功能设置一次?通常,是否可以为所有实现设置公共绑定?

闭包不起作用,因为它null-vector需要一个“参数”,但我想我可以partial它。但是,仍然需要计算size参数。我显然希望避免重复代码。

(defn path
  "Returns a lazy sequence of vectors representing a monotonic path
   walked over coll in n-dimensional space, where n is the cardinality
   of coll's alphabet."

  ([coll]
     (let [alphabet    (set coll)
           cardinality (count alphabet)
           alpha-map   (apply hash-map (interleave alphabet (range cardinality)))
           null-vector (vec (repeat cardinality 0))]
       (path coll null-vector alpha-map)))

  ([coll alpha-map]
     (let [null-vector (vec (repeat (count (keys alpha-map)) 0))]
       (path coll null-vector alpha-map)))

  ([coll origin alpha-map]
     (let [null-vector (vec (repeat (count origin) 0))
           unit-vector #(assoc null-vector (alpha-map %) 1)
           sum-vectors #(vec (map + %1 %2))]
       (reductions sum-vectors origin (map unit-vector coll)))))

1 个答案:

答案 0 :(得分:6)

我会创建一个“私人”辅助函数:

(defn- null-copy-vector [coll]
  (vec (repeat (count coll) 0)))

然后在函数的每个分支中调用它:

(defn path
  "Returns a lazy sequence of vectors representing a monotonic path
   walked over coll in n-dimensional space, where n is the cardinality
   of coll's alphabet."

  ([coll]
     (let [alphabet    (set coll)
           alpha-map   (zipmap alphabet (iterate inc 0))  ;; note 1
           null-vector (null-copy-vector alphabet)]
       (path coll null-vector alpha-map null-vector)))

  ([coll alpha-map]
     (let [null-vector (null-copy-vector alpha-map)]      ;; note 2
        (path coll null-vector alpha-map null-vector))) 

  ([coll origin alpha-map]
     (path coll origin alpha-map (null-copy-vector origin)))

  ([coll origin alpha-map null-vector]
     (let [unit-vector #(assoc null-vector (alpha-map %) 1)
           sum-vectors #(vec (map + %1 %2))]
       (reductions sum-vectors origin (map unit-vector coll)))))

这可能对你不满意,因为null-copy-vector并非“内部”整体功能,但我认为这是非常惯用的。在一个没有多个arities的函数中,我可能会使用letfn来分隔出一个“内部”函数,但这在这里不起作用。

像这样突破也可以让你a)在其他地方重用基本的构建块函数,b)让你在更小的块中进行测试。您可能希望跳过defn-并使用defn来简化测试(尽管可以使用bit more work来测试defn。)

我还打破了一个新的4-arg表单,它将null-vector作为最后一个arg,让你直接传递它,如果你知道它,这样你就可以避免从已经为空的向量重新创建它。如果你想隐藏那个4-arg表格,你可以把它拉成一个单独的defn-helper函数。

无关的说明:

  1. 我使用zipmap和无限序列将您的第一个分支修改为更简单的(imho)impl。
  2. 而不是(count(键映射)),只需执行(计数映射)就足够了(此处的计数在你的辅助函数中)。