Можно ли установить общую привязку для всех реализаций в функции мульти-подписи? - PullRequest
1 голос
/ 03 декабря 2010

(Это вопрос о стиле. Я знаю, что это можно сделать с помощью множества условных выражений, мультиметодов и т. Д.)

В следующей функции null-vector - этоопределяется для каждой реализации.Как я могу установить его один раз для всей функции?В общем, возможно ли установить общую привязку ко всем реализациям?

Закрытие не будет работать, так как оно null-vector нуждается в "аргументе", но я полагаю, я мог бы partial его.Однако для этого все равно потребуется вычисление параметра размера.Я бы хотел избежать повторения кода, очевидно.

(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 Ответ

6 голосов
/ 03 декабря 2010

Я бы создал "приватную" вспомогательную функцию:

(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 не «внутри» общей функции здесь, но я думаю, что это довольно идиоматично.Для функции, которая не принимает несколько арностей, я мог бы использовать letfn , чтобы отделить «внутреннюю» функцию, но это не сработает здесь.

Разделение подобных вещей также позволяет вама) повторно использовать базовые функции строительных блоков в другом месте и б) позволяет тестировать небольшими блоками.Возможно, вы захотите пропустить defn- и просто использовать defn, чтобы упростить тестирование (хотя можно тестировать defn с немного большим количеством работы ).

Я также создал новую форму с четырьмя аргументами, которая принимает нулевой вектор в качестве последнего аргумента, позволяя вам передать его напрямую, если вы знаете его, чтобы избежать повторного создания его из уже нулевого вектора.Если вы хотите скрыть эту 4-аргументную форму, вы можете перетащить ее в отдельную функцию-помощник.

Не связанные заметки:

  1. Я изменил вашу первую ветку на более простую (imho) impl с использованием zipmap и бесконечной последовательности.
  2. Вместо (count (keys keys)) достаточно просто выполнить (map count) (счетчик находится внутри вашей вспомогательной функции).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...