В чем разница между Clojure clojure.core.reducers / fold и Scala fold? - PullRequest
0 голосов
/ 31 августа 2018

Я обнаружил, что Clojure имеет функцию clojure.core.reducers/fold.

Также Scala имеет встроенную функцию fold, но не может понять, что они работают по-другому или нет?

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Я предполагаю, что вы говорите о clojure.core.reducers / fold .

Scala по умолчанию fold реализация последовательностей очень проста:

collection.fold(identityElem)(binOp)

просто начинается с identityElem, затем последовательно проходит сбор и применяет двоичную операцию binOp к уже накопленному результату и текущему значению последовательности, например,

(1 to 3).fold(42000)(_ + _)

приведет к 42000 + 1 + 2 + 3 = 42006.

Clojure's fold с полной подписью

(r/fold n combinef reducef coll)

из вышеупомянутого пакета работает параллельно в два этапа. Сначала он разбивает входные данные на более мелкие группы размером n (приблизительно), затем сокращает каждую группу, используя reducef, и, наконец, объединяет результаты каждой группы, используя combinef.

Основное отличие состоит в том, что combinef, как ожидается, будет одновременно нулевым и бинарным одновременно (Clojure имеет многозадачные функции), и будет вызываться (combinef) (без аргументов) для создания элементов идентификации для каждого раздела (таким образом, эта документация является правильной, а эта документация лежит).

То есть, чтобы смоделировать сгиб Скалы из приведенного выше примера, нужно написать что-то вроде этого:

(require '[clojure.core.reducers :as r])

(r/fold 3 (fn ([] 42000) ([x y] y)) + [1 2 3])

И вообще у Скалы fold

collection.fold(identityElement)(binOp)

можно эмулировать с помощью reducers/fold следующим образом:

(r/fold collectionSize (fn ([] identityElem) ([x y] y)) binOp collection)

(обратите внимание на хитрое ([x y] y), которое отбрасывает первый аргумент, оно намеренно).

Полагаю, интерфейс не был предназначен для использования с любыми нулевыми двоичными операциями, которые не являются моноидами, поэтому Scala fold так неудобно моделировать с использованием Clojure fold. Если вы хотите что-то, что ведет себя как fold Scala, используйте reduce в Clojure.


EDIT

Ой, подожди. Документация фактически заявляет, что

объединение должно быть ассоциативным, и, когда вызывается без arguments, (combf) должен создать свой элемент идентичности

то есть мы на самом деле вынуждены использовать моноид в качестве combinef, поэтому приведенный выше пример 42000, ([x y] y) на самом деле недопустим, а поведение фактически не определено. Тот факт, что я каким-то образом получил 42006, был хаком в строго техническом смысле, поскольку для получения желаемого результата он полагался на неопределенное поведение библиотечной функции 42006.

Принимая во внимание эту дополнительную информацию, я не уверен, что Scala fold может быть имитирован Clojure core.reducers/fold вообще. fold Clojure, кажется, ограничен сокращениями с моноидом, тогда как сгиб Скалы ближе к общему List катаморфизму за счет параллелизма.

0 голосов
/ 31 августа 2018

Пространство имен clojure.core.reducers - это специализированная реализация, предназначенная для параллельной обработки больших наборов данных. Вы можете найти полные документы здесь:

https://clojure.org/reference/reducers.

(r/fold reducef coll)
(r/fold combinef reducef coll)
(r/fold n combinef reducef coll)

r / fold берет приводимый набор и разбивает его на группы примерно n (по умолчанию 512) элементов. Каждая группа сокращается с помощью функция Reduf. Функция Reduf будет вызываться без аргументы для создания значения идентичности в каждом разделе. Результаты, достижения из этих сокращений затем уменьшаются с помощью combf (по умолчанию Reduff) функция. Когда вызывается без аргументов, (combf) должен произвести его элемент идентичности - это будет вызываться несколько раз. Операции могут выполняться параллельно. Результаты сохранят порядок.


До тех пор, пока вы не добьетесь максимальных результатов, просто придерживайтесь базовой функции reduce:

https://clojuredocs.org/clojure.core/reduce

По сути, это то же самое, что и функция Scala fold:

(reduce + 0 [1 2 3 4 5]) => 15

где сигнатура функции:

(reduce <op> <init-val> <collection-to-be-reduced> )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...