В функциональном программировании , сгиб (также называемый сократить , скапливаются , агрегат , компресс или инъецировать ) относится к семейству функций высшего порядка , которые анализируют на рекурсивную структуру данных и за счет использования данной операции комбинирования, рекомбинируют результаты рекурсивно обработки его составные части, создавая возвращаемое значение. Как правило, складка представлена сочетающая функцией , верхний узел в виде структуры данных ,, и, возможно, некоторые значения по умолчанию, которые будут использоваться при определенных условиях. Затем свертка переходит к объединению элементов иерархии структуры данных с систематическим использованием функции.
Сгибы в некотором смысле двойственны для развертываний , которые принимают начальное значение и коркурсивно применяют функцию, чтобы решить, как постепенно построить структуру данных corecursive, тогда как сгиб рекурсивно разрушает эту структуру, заменяя ее результатами применения функции комбинирования на каждый узел по своим конечным значениям и рекурсивным результатам ( катаморфизм против анаморфизма разворотов).
Как структурные преобразования [ править ]
В этом разделе не процитировать любые источники . ( Июнь 2013 г. ) ( Узнайте, как и когда удалить этот шаблон сообщения ) |
Складки можно рассматривать как последовательную замену структурных компонентов структуры данных функциями и значениями. Списки , например, строятся на многих функциональных языках из двух примитивов: любой список является либо пустым списком, обычно называемым nil ( []
), либо создается с помощью префикса элемента перед другим списком, создавая так называемый cons- узел. ( Cons(X1,Cons(X2,Cons(...(Cons(Xn,nil)))))
), полученный в результате применения cons
функции (записанной (:)
в Haskell как двоеточие ). Можно просмотреть раз в списках , как замена на ноль в конце списка со значением определенной, и заменяя друг противс определенной функцией. Эти замены можно рассматривать в виде диаграммы:
Есть еще один способ выполнить структурное преобразование согласованным образом, с изменением порядка двух ссылок каждого узла при подаче в функцию комбинирования:
Эти изображения наглядно иллюстрируют правую и левую складку списка . Они также подчеркивают тот факт, что foldr (:) []
это функция идентификации в списках ( неглубокая копия на языке Лиспа ), поскольку замена cons на cons
и nil на nil
не изменит результат. Левая диаграмма складки предполагает простой способ полностью изменить список, foldl (flip (:)) []
. Обратите внимание, что параметры cons должны быть перевернуты, потому что добавляемый элемент теперь является правым параметром функции объединения. Еще один простой результат, который можно увидеть с этой точки зрения, - это написать функцию карты более высокого порядка в терминахfoldr
, составив функцию, которая будет воздействовать на элементы cons
, как:
карта е = foldr (( : ) . е ) []
где точка (.) - оператор, обозначающий композицию функции .
Такой взгляд на вещи обеспечивает простой путь к разработке функций, подобных свертке, для других алгебраических типов данных и структур, таких как различные виды деревьев. Один пишет функцию, которая рекурсивно заменяет конструкторы типа данных предоставленными функциями, а любые постоянные значения типа предоставленными значениями. Такую функцию обычно называют катаморфизмом .
В списках [ править ]
Свертывание списка [1,2,3,4,5]
с помощью оператора сложения приведет к 15 - сумме элементов списка [1,2,3,4,5]
. В грубом приближении эту складку можно представить как замену запятых в списке операцией +, давая 1 + 2 + 3 + 4 + 5
.
В приведенном выше примере + - это ассоциативная операция , поэтому конечный результат будет одинаковым независимо от скобок, хотя конкретный способ его вычисления будет другим. В общем случае неассоциативных бинарных функций порядок, в котором объединяются элементы, может влиять на значение конечного результата. В списках есть два очевидных способа сделать это: либо комбинируя первый элемент с результатом рекурсивного комбинирования остальных (называемых правой складкой ), либо комбинируя результат рекурсивного комбинирования всех элементов, кроме последнего, с последний элемент (называемый левой складкой ). Это соответствует тому, что бинарный оператор в Haskell является либо правоассоциативным, либо левоассоциативным.«S или Пролог » s терминологии. При правой складке сумма будет заключена в скобки как 1 + (2 + (3 + (4 + 5)))
, а при левой складке она будет заключена в скобки как (((1 + 2) + 3) + 4) + 5
.
На практике удобно и естественно иметь начальное значение, которое в случае правой складки используется, когда кто-то достигает конца списка, а в случае левой складки - это то, что изначально объединяется с первым элементом списка. список. В приведенном выше примере значение 0 ( аддитивная идентичность ) будет выбрано в качестве начального значения 1 + (2 + (3 + (4 + (5 + 0))))
для правой и ((((0 + 1) + 2) + 3) + 4) + 5
левой складок. Для умножения, первоначальный выбор-не будет работать: 0 * 1 * 2 * 3 * 4 * 5 = 0
. Элемент идентичности для умножения равен 1. Это даст нам результат 1 * 1 * 2 * 3 * 4 * 5 = 120 = 5!
.
Линейные складки против древовидных [ править ]
Использование начального значения необходимо, когда функция комбинирования f асимметрична по своим типам (например, a → b → b
), то есть когда тип ее результата отличается от типа элементов списка. Затем необходимо использовать начальное значение того же типа, что и результат f , чтобы была возможна линейная цепочка приложений. Будет ли он ориентирован влево или вправо, будет определяться типами, ожидаемыми от его аргументов функцией комбинирования. Если это второй аргумент, который должен быть того же типа, что и результат, тогда f можно рассматривать как двоичную операцию, которая связывает справа , и наоборот.
Когда функция является магма , т.е. симметрична его типов ( a → a → a
), и тип результата такой же , как тип элементов списка, скобки могут быть размещены в произвольном порядке , таким образом , создавая дерево вложенных подвыражения, например, ((1 + 2) + (3 + 4)) + 5
. Если двоичная операция f ассоциативна, это значение будет четко определено, то есть одинаковым для любых скобок, хотя рабочие детали того, как она вычисляется, будут другими. Это может существенно повлиять на эффективность, если f не является строгим .
В то время как линейные складки являются узлом-ориентированным и работают согласованно для каждого узла в виде списка , древовидная складки всего список-ориентированные и действует последовательным образом через группу узлов.
Специальные складки для непустых списков [ править ]
Часто хочется выбрать единичный элемент операции f в качестве начального значения z . Когда исходное значение не кажется подходящим, например, когда кто-то хочет свернуть функцию, которая вычисляет максимум из двух ее параметров, по непустому списку, чтобы получить максимальный элемент списка, существуют варианты foldr
и, foldl
которые используют последний и первый элемент списка соответственно в качестве начального значения. В Haskell и некоторых других языках они называются foldr1
and foldl1
, причем 1 ссылается на автоматическое предоставление начального элемента и на тот факт, что списки, к которым они применяются, должны иметь по крайней мере один элемент.
Эти свертки используют симметричную по типу бинарную операцию: типы ее аргументов и ее результата должны быть одинаковыми. Ричард Берд в своей книге 2010 года предлагает [1] «общую функцию сворачивания для непустых списков», foldrn
которая преобразует свой последний элемент, применяя к нему дополнительную функцию аргумента, в значение типа результата перед началом самого сворачивания, и таким образом, может использовать двоичную операцию с асимметричным типом, такую как обычная, foldr
для получения результата, тип которого отличается от типа элементов списка.
Реализация [ править ]
Линейные складки [ править ]
Использование Haskell в качестве примера, foldl
и foldr
может быть сформулирована в нескольких уравнений.
foldl :: ( b -> a -> b ) -> b -> [ a ] -> b foldl f z [] = z foldl f z ( x : xs ) = foldl f ( f z x ) xs
Если список пуст, результатом будет начальное значение. Если нет, сверните хвост списка, используя в качестве нового начального значения результат применения f к старому начальному значению и первому элементу.
foldr :: ( a -> b -> b ) -> b -> [ a ] -> b foldr f z [] = z foldr f z ( x : xs ) = f x ( foldr f z xs )
Если список пуст, результатом будет начальное значение z. Если нет, примените f к первому элементу и результату свертывания остальных.
Древовидные складки [ править ]
Списки могут быть свернуты древовидным способом как для конечных, так и для неопределенно определенных списков:
foldt f z [] = z foldt f z [ x ] = f x z foldt f z xs = foldt f z ( пары f xs ) foldi f z [] = z foldi f z ( x : xs ) = f x ( foldi f z ( пары f xs )) пары f ( x : y : t ) = f x y : пары f t пары _ t = t
В случае foldi
функции, чтобы избежать ее неконтролируемого вычисления в неопределенно определенных списках, функция не всегдаf
должна запрашивать значение своего второго аргумента, по крайней мере, не все, или не сразу (см. Пример ниже).
Складки для непустых списков [ править ]
foldl1 f [ x ] = x foldl1 f ( x : y : xs ) = foldl1 f ( f x y : xs )foldr1 f [ x ] = x foldr1 f ( x : xs ) = f x ( foldr1 f xs )foldt1 f [ x ] = x foldt1 f ( x : y : xs ) = foldt1 f ( f x y : пары f xs ) foldi1 f [ x ] = x foldi1 f ( x : xs ) = f x ( foldi1 f ( пары f xs ))
Рекомендации по порядку оценки [ править ]
При наличии ленивого или нестрогого вычисления foldr
немедленно возвращает приложение f в начало списка и рекурсивный случай сворачивания по остальной части списка. Таким образом, если f может произвести некоторую часть своего результата без ссылки на рекурсивный случай «справа», то есть во втором аргументе, а остальная часть результата никогда не требуется, то рекурсия остановится (например, ) . Это позволяет правым сверткам работать с бесконечными списками. Напротив, немедленно вызовет себя с новыми параметрами, пока не достигнет конца списка. Эта хвостовая рекурсияhead == foldr (\a b->a) (error "empty list")
foldl
может быть эффективно скомпилирован как цикл, но вообще не может работать с бесконечными списками - он будет рекурсивно повторяться бесконечно в бесконечном цикле .
Дойдя до конца списка, выражение является в действительности построен foldl
гнездовыми левыми углубления f
-applications, который затем вызывающий абонент для оценки. Если бы функция f
здесь сначала ссылалась на свой второй аргумент и могла бы произвести некоторую часть своего результата без ссылки на рекурсивный случай (здесь, слева, то есть в своем первом аргументе), то рекурсия остановилась бы. Это означает, что при foldr
рекурсии справа она позволяет функции ленивого комбинирования проверять элементы списка слева; и наоборот, а foldl
рекурсии слева, он позволяет функции ленивого комбинирования проверять элементы списка справа, если она того пожелает (например, ).last == foldl (\a b->b) (error "empty list")
Обращение списка также является хвостовой рекурсией (это можно реализовать с помощью ). В конечных списках это означает, что можно составить левую и обратную складку для выполнения правой свертки хвостовой рекурсией (см. ), С модификацией функции, чтобы она меняла порядок своих аргументов (т. Е. ), tail-рекурсивно строит представление выражения, которое будет строить правый. Посторонняя промежуточная структура списка может быть устранена с продолжением прохождения стиля техникой, ; аналогично ( требуется только в таких языках, как Haskell, с перевернутым порядком аргументов для функции объединенияrev = foldl (\ys x -> x : ys) []
1+>(2+>(3+>0)) == ((0<+3)<+2)<+1
f
foldr f z == foldl (flip f) z . foldl (flip (:)) []
foldr f z xs == foldl (\k x-> k . f x) id xs z
foldl f z xs == foldr (\x k-> k . flip f x) id xs z
flip
foldl
в отличие, например, от схемы, где один и тот же порядок аргументов используется для объединения функций с обоими foldl
и foldr
).
Другой технический момент заключается в том, что в случае левых сверток с использованием ленивого вычисления новый начальный параметр не оценивается до выполнения рекурсивного вызова. Это может привести к переполнению стека, когда кто-то достигает конца списка и пытается оценить получившееся потенциально гигантское выражение. По этой причине такие языки часто предоставляют более строгий вариант сворачивания влево, который заставляет вычислять начальный параметр перед выполнением рекурсивного вызова. В Haskell это foldl'
функция (обратите внимание на апостроф, произносится как «премьер») вData.List
библиотека (необходимо помнить о том, что форсирование значения, созданного с помощью ленивого конструктора данных, само по себе не приведет к автоматическому форсированию его составляющих). В сочетании с хвостовой рекурсией такие складки приближаются к эффективности циклов, обеспечивая постоянную пространственную операцию, когда ленивая оценка конечного результата невозможна или нежелательна.
Примеры [ править ]
Используя интерпретатор Haskell , структурные преобразования, выполняемые функциями свертки, можно проиллюстрировать построением строки:
λ > foldr ( \ x y -> concat [ "(" , x , "+" , y , ")" ]) "0" ( показать карту [ 1 .. 13 ]) "(1+ (2+ (3 + (4+ (5+ (6+ (7+ (8+ (9+ (10+ (11+ (12+ (13 + 0))))))))))))) " λ > foldl ( \ x y -> concat [ "(" , x , "+" , y , ")" ]) "0" ( показать карту [ 1 .. 13 ]) "(((((((( (((((0 + 1) +2) +3) +4) +5) +6) +7) +8) +9) +10) +11) +12) +13) " λ > foldt ( \ x y -> concat [ "(" , x , "+" , y , ")" ]) "0" ( показать карту [ 1 .. 13 ]) "(((((1 + 2 ) + (3 + 4)) + ((5 + 6) + (7 + 8))) + (((9 + 10) + (11 + 12)) + 13)) + 0) " λ > foldi ( \ x y -> concat [ "(" , x , "+" , y , ")" ]) "0" ( показать карту [ 1 .. 13 ]) "(1 + ((2 + 3 ) + (((4 + 5) + (6 + 7)) + ((((8 + 9) + (10 + 11)) + (12 + 13)) + 0)))) "
Бесконечное древовидное сворачивание демонстрируется, например, в рекурсивном производстве простых чисел неограниченным решетом Эратосфена в Haskell :
простые числа = 2 : _Y (( 3 : ) . минус [ 5 , 7 .. ] . Фелди ( \ ( х : XS ) YS -> х : объединение хз YS ) [] . карта ( \ р -> [ р * р , p * p + 2 * p .. ])) _Y g = g ( _Y g ) - = g. грамм . грамм . грамм . ...
где функция unionработает с упорядоченными списками локально, чтобы эффективно произвести их объединение множеств и minusих разность множеств .
Для конечных списков, например, сортировку слиянием (и ее разновидность удаления дубликатов nubsort
) можно легко определить с помощью древовидной свертки как
mergesort xs = foldt merge [] [[ x ] | x <- xs ] nubsort xs = foldt union [] [[ x ] | x <- xs ]
с функцией mergeсохранения дубликатов union
.
Функции head
и last
могли быть определены путем сворачивания как
head = foldr ( \ x r -> x ) ( ошибка «head: пустой список» ) last = foldl ( \ a x -> x ) ( ошибка «last: пустой список» )
На разных языках [ править ]
Язык | Левая складка | Правый сгиб | Левый сгиб без начального значения | Правый сгиб без начального значения | Развернуть | Заметки | |
---|---|---|---|---|---|---|---|
APL | func⍨/⌽initval,vector | func/vector,initval | func⍨/⌽vector | func/vector | |||
C # 3.0 | ienum | ienum.Reverse() | ienum | ienum.Reverse() | Агрегат представляет собой метод расширения ienum является IEnumerable<T> Аналогично во всех языках .NET | ||
C ++ | std::accumulate( | std::accumulate( | в заголовке <numeric> begin , end , rbegin , rend - итераторы. func может быть указателем на функцию или объектом функции. | ||||
C ++ 17 | (initval op ... op pack) | (pack op ... op initval) | (... op pack) | (pack op ...) | Выражение свертки (только для шаблонов функций с переменным числом аргументов): op - это бинарный оператор (оба op должны быть одинаковыми, например, (std::cout << ... << args) ), pack - это нерасширенный пакет параметров. | ||
CFML | obj.reduce(func,initial) | obj.reduce(func) | Где func получает в качестве аргументов результат предыдущей операции (или initial значение на первой итерации); текущий элемент; индекс или ключ текущего элемента; и ссылка наobj | ||||
Clojure | (reduce func initval list) | (reduce func initval (reverse list')) | (reduce func list) | (reduce func" (reverse list)) | См. Также clojure.core.reducers / fold | ||
Common Lisp | (reduce func list :initial-value initval) | (reduce func list :from-end t :initial-value initval) | (reduce func list) | (reduce func list :from-end t) | |||
Завиток | {{TreeNode.default treeNode ...} .to-Iterator} | {{TreeNode.default treeNode ...} .reverse} | {for {treeNode | {for {{treeNode.reverse} | также реализуют DefaultListModel и HashTable to-Iterator | ||
D | reduce!func(initval, list) | reduce!func(initval, list | reduce!func(list) | reduce!func( | в модуле std.algorithm | ||
Эликсир | List.foldl(list, acc, fun) | List.foldr(list, acc, fun) | См. Документацию для примера использования | ||||
Вяз | List.foldl(Fun, Accumulator, List) | List.foldr(Fun, Accumulator, List) | См. Также List API [1] | ||||
Erlang | lists:foldl(Fun, Accumulator, List) | lists:foldr(Fun, Accumulator, List) | |||||
F # | Seq/List.fold func initval list | List.foldBack func list initval | Seq/List.reduce func list | List.reduceBack func list | Seq.unfold func initval | ||
Госу | Iterable.fold(f(agg, e)) | Все это методы расширения в интерфейсе Iterable Java, также поддерживаются массивы. | |||||
Groovy | list | list.reverse() | list | list.reverse() | |||
Haskell | foldl func initval list | foldr func initval list | foldl1 func list | foldr1 func list | unfoldr func initval | Для foldl функция сворачивания принимает аргументы в порядке, обратном порядку для foldr. | |
Haxe | Lambda.fold(iterable, func, initval) | ||||||
J | verb~/|. initval,array | verb/ array,initval | verb~/|. array | verb/ array | u / y применяет диаду u между элементами y. "J Dictionary: Insert" | ||
Java 8+ | stream.reduce | stream.reduce | |||||
JavaScript 1.8 ECMAScript 5 | array.reduce | array.reduceRight | array.reduce | array.reduceRight | |||
Юлия | foldl(op, itr; [init]) | foldr(op, itr; [init]) | foldl(op, itr) | foldr(op, itr) | |||
Котлин | Iterable.fold | Iterable.foldRight | Iterable.reduce(func) | Iterable .reduceRight(func) | Другие коллекции также поддерживают fold [2] и reduce . [3] Существует также Result.fold(onSuccess, onFailure) , [4], который сводит Result<T> (успех или неудачу) к типу возврата onSuccess и onFailure . | ||
LFE | (lists:foldl func accum list) | (lists:foldr func accum list) | |||||
Logtalk | fold_left(Closure, Initial, List, Result) | fold_right(Closure, Initial, List, Result) | Мета-предикаты, предоставляемые объектом стандартной мета- библиотеки. Также могут использоваться сокращения foldl и foldr . | ||||
Клен | foldl(func, initval, sequence) | foldr(func, initval, sequence) | |||||
Mathematica | Fold[func, initval, list] | Fold[func, initval, Reverse[list]] | Fold[func, list] | Fold[func, Reverse[list]] | NestWhileList[func,, initval, predicate] | Fold без начального значения поддерживается в версиях 10.0 и выше. | |
MATLAB | fold(@func, list, defaultVal) | fold(@func, flip(list), defaultVal) | fold(@func, list) | fold(@func, flip(list)) |
| Требуется Symbolic Math Toolbox, поддерживаемый с R2016b. | |
Максима | lreduce(func, list, initval) | rreduce(func, list, initval) | lreduce(func, list) | rreduce(func, list) | |||
Мифрил | fold_left func initval list | fold_right func initval list | Предоставленная функция принимает свои аргументы в виде кортежа. | ||||
OCaml | List.fold_left func initval list | List.fold_right func list initval | Base.Sequence.unfold ~init ~f [5] | ||||
Унция | {FoldL List Func InitVal} | {FoldR List Func InitVal} | |||||
PARI / GP | fold( f, A ) | ||||||
Perl | reduce block initval, list | reduce block list | в List::Util модуле | ||||
PHP | array_reduce(array, func, initval) | array_reduce( | array_reduce(array, func) | array_reduce( | Если initval не указан, используется NULL, так что это не настоящий foldl1. До PHP 5.3 initval может быть только целым числом. "func" - это обратный вызов . Попробуйте array_reduce в Интернете. | ||
Python 2.x | reduce(func, list, initval) | reduce(lambda x,y: func(y,x), reversed(list), initval) | reduce(func, list) | reduce(lambda x,y: func(y,x), reversed(list)) | |||
Python 3.x | functools.reduce(func, list, initval) | functools.reduce(lambda x,y: func(y,x), reversed(list), initval) | functools.reduce(func, list) | functools.reduce(lambda x,y: func(y,x), reversed(list)) | В модуле functools . [6] | ||
р | Reduce(func, list, initval) | Reduce(func, list, initval, right=TRUE) | Reduce(func, list) | Reduce(func, list, right=TRUE) | R поддерживает свертывание вправо и влево или вправо с или без начального значения через аргументы right и init функции Reduce. | ||
Рубин | enum | enum.reverse_each | enum | enum.reverse_each | В Ruby 1.8.7+ можно также передавать символ, представляющий функцию, вместо блока. enum - это перечисление. Обратите внимание, что эти реализации правильных складок неверны для некоммутативного & block (также начальное значение помещается на неправильную сторону). | ||
Ржавчина | iterator.fold(initval, func) | iterator.rev().fold(initval, func) | |||||
Scala | list.foldLeft(initval)(func) (initval /: list)(func) | list.foldRight(initval)(func) (list :\ initval)(func) | list.reduceLeft(func) | list.reduceRight(func) | Синтаксис символической складки в Scala был призван напоминать дерево, наклоняющееся влево или вправо, обычно используемое для объяснения операции складывания [7], но с тех пор было переинтерпретировано как иллюстрация опрокидывающегося домино. [8] Двоеточие происходит от общего синтаксического механизма Scala, посредством которого очевидный инфиксный оператор вызывается как метод для левого операнда с правым операндом, переданным в качестве аргумента, или наоборот, если последний символ оператора является двоеточием, здесь применяется симметрично. . В Scala также есть древовидные складки, использующие этот метод | ||
Схема R 6 RS | (fold-left func initval list) | (fold-right func initval list) | (reduce-left func defaultval list) | (reduce-right func defaultval list) | srfi / 1 srfi / 43 | ||
Болтовня | aCollection inject: aValue into: aBlock | aCollection reduce: aBlock | ANSI Smalltalk не определяет #reduce: но есть во многих реализациях. | ||||
Стандартный ML | foldl func initval list | foldr func initval list | Предоставленная функция принимает свои аргументы в виде кортежа. Для foldl функция сворачивания принимает аргументы в том же порядке, что и для foldr. | ||||
Быстрый | array.reduce(initval, func) | array.reverse() | |||||
XPath 3.1 | array:fold-left(
| array:fold-right(
| В XPath 3.1 в силу исторических причин, array и sequence типы несовместимы - таким образом , потребность в отдельных fold функций для array и дляsequence
| ||||
Xtend | iterable.fold(initval,[func]) | iterable.reduce[func] |
Универсальность [ править ]
Fold - это полиморфная функция. Для любого g, имеющего определение
g [] = v g ( x : xs ) = f x ( g xs )
тогда g можно выразить как [10]
g = foldr f v
Кроме того, комбинатор с фиксированной точкой может быть реализован через свертку, [11] доказывая, что итерации могут быть сведены к сверткам:
y f = foldr ( \ _ -> f ) undefined ( повторение не определено )
См. Также [ править ]
- Агрегатная функция
- Итерированная бинарная операция
- Катаморфизм , обобщение складки
- Гомоморфизм
- Карта (функция высшего порядка)
- Сумма префикса
- Рекурсивный тип данных
- Оператор редукции
- Структурная рекурсия
Ссылки [ править ]
- ^ Ричард Берд, «Жемчужины проектирования функциональных алгоритмов», Cambridge University Press 2010, ISBN 978-0-521-51338-8 , стр. 42
- ^ "fold - язык программирования Kotlin" . Котлин . Jetbrains . Проверено 29 марта 2019 .
- ^ "reduce - язык программирования Kotlin" . Котлин . Jetbrains . Проверено 29 марта 2019 .
- ^ "Результат - язык программирования Котлин" . Котлин . Jetbrains . Проверено 29 марта 2019 .
- ^ "База" . Джейн Стрит Кэпитал . Проверено 26 февраля 2019 года .
- ^
Для справки
functools.reduce
:import functools
Для справкиreduce
:from functools import reduce
- ^ Одерски, Martin (2008-01-05). «Re: Blog: Мой вердикт языку Scala» . Группа новостей : comp.scala.lang . Проверено 14 октября 2013 года .
- ^ Стерлинг, Николас. «Интуитивно понятный оператор Scala /: (foldLeft)» . Проверено 24 июня +2016 .
- ^ «Fold API - Стандартная библиотека Scala» . www.scala-lang.org . Проверено 10 апреля 2018 .
- ^ Хаттон, Грэм. «Учебник по универсальности и выразительности складки» (PDF) . Журнал функционального программирования (9 (4)): 355–372 . Проверено 26 марта 2009 года .
- ↑ Папа, Берни. «Получение исправления из правильной складки» (PDF) . Монада. Чтение (6): 5–16 . Проверено 1 мая 2011 года .
Внешние ссылки [ править ]
- «Функции высшего порядка - отображение, сворачивание и фильтрация»
- «Блок 6: Функции складывания высшего порядка»
- "Сложить в Tcl"
- «Построение гомоморфизма списков из левых и правых складок»
- "Волшебный фолдр"