В течение некоторого времени я спрашивал себя, есть ли способ определить функцию с более чем одной вариационной перегрузкой. Вот пример функции я писал (я знаю, что нет никакого управления исключением, плюс, может быть, есть лучший способ, чтобы закодировать его -Вообще я не отлаживать его, - но я просто сосредоточиться здесь на VARIADIC аспекте):Clojure: более 1 вариационная перегрузка, более идиоматический способ сделать?
(defn write-csv
"Writes a csv from data that is already formatted for clojure.data.csv/write-csv or not.
In the second case, the function guesses a header and writes it. Can handle three types of
data : nested rows (example : {1 {:a 2 :b 3} 2 {:a 25 :b 17} ...), flattened data (like the one you use
in clj-data-process-utils.data (example : ({:id 1 :a 2 :b 3} {:id 2 :a 25 :b 17} ...)) or already formatted
data (example : [['ID' 'B' 'C'] [1 2 3] [2 25 17]]). Note that in the last case you have to provide a header if you want one.
The guesses can be overriden by the :header arg. Optimized for Excel with default values.
Input :
- data : data to write as CSV
- path : the filepath of the new CSV
- (optional) sep : the separator to use, must be of type char [default : ;]
- (optional) dec : the decimal separator to use, must be of type char [default : .]
- (optional) newline : the newline character, see cljure.data.csv options, default here for windows [default : :cr+lf]
- (optional) header : if you want to provide your own data, pass here a vector of columns names, guesses by default if data is not formatted [default : :guess]"
[data path & {:keys [sep dec newline header] :or {sep \; dec \. newline :cr+lf header :guess}}]
(let [f-data (cond (or (map? data) (seq? data))
(cond (vec? header)
(format-for-csv sep data header)
(= :guess header)
(->> (guess-header data)
(format-for-csv sep data)))
(vec? data)
data)
wrtr (io/writer path)]
(csv/write-csv wrtr f-data :separator sep :newline newline)))
Как вы можете видеть, мы можем дополнительно передать заголовок. Я положил его на дополнительные ключи, но я предпочел бы иметь что-то подобное в первом случае (даже если это aritties карта нормально для меня):
(defn write-csv
([data path & {:keys [sep dec newline] :or {sep \; dec \. newline :cr+lf}}]
...)
([data header path & {:keys [sep dec newline] :or {sep \; dec \. newline :cr+lf}}]
...))
Конечно, это не работает, потому что мы не можем имеют более 1 вариационной перегрузки. Я предпочитаю его только потому, что он более понятен для конечного пользователя.
Я так учил о двух вещах:
- с использованием второй собственной функции с применить ... но это не решает проблему в Teh первой isntance, потому что я хочу два возможных стилей входов.
- Я огляделась
defmulti
, но я видел, что он также принимает те же арностей для каждого submethods
Конечно, я могу также разделить функции на два или два случая в первом арг (вектор с типами [ векторная карта] будет означать, что пользователь передает не форматированные данные + заголовок), но хуже для пользователя. Я действительно хочу предложить эти возможности ввода.
Есть ли что-то, что я не заметил в функциях clojure или это более глубокая проблема, которую мы не можем решить?
Спасибо!
Вы можете передать все эти параметры ('sep dec newline') в качестве карты вместо пары ключ-значение. – OlegTheCat
Возможно, но у меня будет проблема arity, которую я могу решить с defmulti. Таким образом, это решение, но теперь параметры находятся в хэшмапе, что менее интуитивно для старых пользователей python/r. Но все же это очень хорошая идея и, возможно, больше в стиле Clojure! –