Clojure: составьте функции arity 2 (или выше)


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

(defn example [data]
  (do-things-to data))

Мой поток заявок будет

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

Макет:

(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, Прежде чем comping 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 2

2 ответа:

Как вы упомянули в своем редактировании, вы действительно можете отобразить свои функции в новые функции, которые имеют root запеченные в:

(mapv #(partial % root) vector-of-functions)

Во-первых, я чувствую, что здесь происходит смесь многих вещей:

  1. (filter identity) является преобразователем, но ничто не говорит о том, что другие ФНС возвращают преобразователи или если обертка ожидает преобразователь, и учитывая, что некоторые из них получат два аргумента, мы можем с уверенностью сказать, что они не являются преобразователями. Вы, вероятно, хотели (partial filter identity) или #(filter identity %).

  2. Почему вы используете (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]) при применении