Clojure: составьте функции arity 2 (или выше)
Я обрабатываю данные с переменным числом функций, зависящих от параметров. Каждая из функций обработки будет получать данные от своей предшественницы, обрабатывать их и передавать следующей функции.
(defn example [data]
(do-things-to data))
Мой поток заявок будет
- проверьте параметры и сохраните необходимые функции в векторе
- создайте функцию, содержащую все необходимые шаги
- вызов функции-оболочки, которая выполняет управление файлами и, наконец, применяет функция
Макет:
(let [my-big-fun (reduce comp (filter identity) vector-of-functions)]
(wrapper lots-a-arguments big-fun)
Теперь я понял, что мне нужно не только передать данные в функции, но и другой набор данных.
(defn new-fun-example [root data]
(do-things-to-both root data))
Есть ли способ сделать что-то подобное редукции, которую я сделал для функции arity-1? Простой juxt
не подойдет, так как каждая функция изменяет данные, необходимые следующей. Возврат seq '(root data)
или подобных ему потребует большого количества переписывания во многих функциях.
Есть идеи? Я предполагаю, что ответ будет "макро", но я никогда возился с ними...
Edit1:
Второй аргумент-это ссылка на растущую графовую структуру данных, поэтому он не нуждается в обработке функциями, просто передается каким-то образом. Но функции могут происходить из разных пространств имен, поэтому я не могу просто поместить корень в более высокую область для доступа к нему. Глобальныйdef
был бы возможен, но чрезвычайно уродлив...
Когда я писал это, я просто подумал, что могу каким-то образом сопоставить функции с partial
, Прежде чем comp
ing them.
Edit2:
filter identity
вызвало много путаницы, это не часть моего вопроса. Я не должен был включать его в свой образец с самого начала. Я решил задачу, предложенную быстрым коричневым Лисом, и прошу прощения за то, что иногда был неясен. Пример минимального решения:
(defn example [root data]
(swap! root + data))
(defn fn-chainer [vector-of-functions]
(let [the-root (atom 0)
; this filter step is just required to remove erroneously apperaring nils
; from the vector of functions - not part of the question
vector-of-functions (filter identity vector-of-functions)
; bake the atom to the functions
vector-of-functions (mapv #(partial % the-root) vector-of-functions)
; now chain each funcion's result as argument to the next one
my-big-fun (reduce comp vector-of-functions)]
; let the function chain process some dataset
(my-big-fun 5))
; test some function vectors
(fn-chainer [example])
=> 5 ; = 0 + 5
(fn-chainer [example example])
=> 10 ; = 0 + 5 +5
(fn-chainer [example nil example example nil nil])10
=> 20 ; = 0 + 5 + 5 + 5 + 5, nils removed
2 ответа:
Как вы упомянули в своем редактировании, вы действительно можете отобразить свои функции в новые функции, которые имеют
root
запеченные в:(mapv #(partial % root) vector-of-functions)
Во-первых, я чувствую, что здесь происходит смесь многих вещей:
(filter identity)
является преобразователем, но ничто не говорит о том, что другие ФНС возвращают преобразователи или если обертка ожидает преобразователь, и учитывая, что некоторые из них получат два аргумента, мы можем с уверенностью сказать, что они не являются преобразователями. Вы, вероятно, хотели(partial filter identity)
или#(filter identity %)
.Почему вы используете
(reduce comp (filter identity) vector-of-functions)
вместо(apply comp (cons (partial filter identity) vector-of-functions)
?Фокусируясь на том, как составить функции, учитывая, что некоторые из они получают больше аргументов, для которых у вас уже есть значение, вы можете использовать partial:
(let [root [1 2 3] other-root [4 5 6] vector-of-functions [(partial filter identity) example (partial my-fun-example root) (partial other-fun-example root other-root)] my-big-fun (apply comp vector-of-functions)] (wrapper lots-a-arguments big-fun))
EDIT: я ошибся в использовании
reverse
для apply comp выше,(reduce comp [fn1 fn2 fn3])
вернет тот же результат, что и(apply comp [fn1 fn2 fn3])
при применении