Промежуточные этапы между вторым и третьим примерами являются такими же для данного конкретного примера. Это связано с тем, что map и фильтр реализованы как ленивые преобразования последовательности в последовательность, о чем вы, несомненно, уже знаете.
Варианта измерительного преобразователя карты и фильтра определяется с использованием того же существенных функциональными возможностями как версии не-преобразователей, за исключением того, что способ, которым они «Conj» (или нет, в случае фильтра) на поток результата является определенном в другом месте. Действительно, если и посмотреть на источник для карты, то используются explicit data-structure construction functions, тогда как transducer variant не использует такие функции - они передаются через rf
. Явно используя cons
в версиях без преобразователя означает, что они всегда будет иметь дело с последовательностями
IMO, основное преимущество использования преобразователей заключается в том, что у вас есть возможность определить pro cess, что вы удаляете вещь, которая будет использовать ваш процесс. Поэтому, возможно, более интересным переписывание вашего третьего примера может быть:
(def process (comp (filter even)
(map #(* 7 %))))
(defn f [coll] (transduce process + collection))
Его упражнением автору приложения, чтобы решить, когда такого рода абстракции необходимо, но это определенно может открыть возможность для повторного использования.
Это может произойти с вами, что вы можете просто переписать
(defn process [coll]
((comp
(partial map #(* 7 %)
(partial filter even?)) coll))
(reduce + (process coll))
И получить тот же эффект; это правда. Когда ваш вход всегда представляет собой последовательность (или всегда тот же тип потока/вы знаете, какой поток он будет), возможно, нет веской причины для создания преобразователя. Но сила повторного использования может быть продемонстрирована здесь (предположит, что процесс представляет собой преобразователь)
(chan 1 process) ;; an async channel which runs process on all inputs
(into [] process coll) ;; writing to a vector
(transduce + process coll) ;; your goal
Мотивация преобразователей, по сути, чтобы остановить, чтобы писать новые функции сбора для различных типов коллекций.Рич Хикки упоминает свое разочарование писать функции как карта < карта> mapcat < mapcat>, и так далее в библиотеке ядра асинхронного - , что карта и mapcat являются, уже определены, а потому, что они предположить, что они работают на последовательностях (которые явным образом связаны с cons
), они не могут применяться к асинхронным каналам. Но каналы могут поставлять свои собственные rf
в версии преобразователя, чтобы они могли повторно использовать эти функции.
Я не думаю, что 'сокращение' является стандартной функцией Haskell. Хотя я предполагаю, что вы, вероятно, имеете в виду один из ['foldr1'] (https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Foldable.html#v:foldr1) или [' foldl1'] (https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Foldable.html#v:foldl1). – Alec
Вы правы, я их перепутал. –
В зависимости от того, скомпилирована ли вы с оптимизацией, первая подвержена потоку слияния, поэтому она почти наверняка закончится запуском как один закрытый цикл (без дополнительных промежуточных распределений). Я считаю, что преобразователи дают вам аналогичные (если не такие мощные/нет накладные расходы), поэтому третий пример должен работать как первый. С другой стороны, второй почти наверняка намного менее эффективен - вы в конечном итоге создадите промежуточные списки, которые в любом случае собираются с мусором. – Alec