Какая разница между ними?
В Википедии мало информации и нет четкого кода, объясняющего эти термины.
Каковы некоторые очень простые примеры, объясняющие эти термины?
Как corecursion двойственна рекурсии?
Существуют ли классические corecusive алгоритмы?
algorithms
recursion
user167908
источник
источник
Ответы:
Есть несколько хороших способов посмотреть на это. Самая легкая вещь для меня - подумать об отношении между «индуктивными» и «коиндуктивными определениями»
Индуктивное определение множества выглядит следующим образом.
Набор «Nat» определяется как наименьший набор, такой, что «Ноль» находится в Nat, а если n - в Nat, «Succ n» - в Nat.
Что соответствует следующему Ocaml
Об этом определении следует отметить, что число
НЕ является членом этого набора. Почему? Предположим, что это так, теперь рассмотрим множество N, которое имеет все те же элементы, что и Nat, за исключением того, что оно не содержит омеги. Ясно, что ноль находится в N, и если y находится в N, Succ (y) находится в N, но N меньше, чем Nat, что является противоречием. Итак, омега не в нат.
Или, может быть, более полезным для ученого:
При некотором наборе «a», набор «List of a» определяется как наименьший набор, такой, что «Nil» находится в List of a, и что, если xs находится в List of a, а x находится в «Cons x xs» находится в списке.
Что соответствует чему-то вроде
Оперативное слово здесь «самое маленькое». Если бы мы не сказали «самый маленький», у нас не было бы никакого способа сказать, содержал ли банан Nat набор!
Очередной раз,
не является допустимым определением для списка натс, так же как омега не был действительным нат.
Такое индуктивное определение данных позволяет нам определять функции, которые работают с ними, используя рекурсию
затем мы можем доказать факты об этом, например, «плюс ноль = а», используя индукцию (в частности, структурную индукцию)
Наше доказательство проводится структурной индукцией по a.
Для базового случая пусть будет ноль.
plus Zero Zero = match Zero with |Zero -> Zero | Succ(c) -> let r = plus c b in Succ(r)
Итак, мы знаемplus Zero Zero = Zero
. Позвольтеa
быть нац. Предположим, что индуктивная гипотезаplus a Zero = a
. Покажем теперь, чтоplus (Succ(a)) Zero = Succ(a)
это очевидно, так какplus (Succ(a)) Zero = match a with |Zero -> Zero | Succ(a) -> let r = plus a Zero in Succ(r) = let r = a in Succ(r) = Succ(a)
по индукцииplus a Zero = a
для всехa
вКонечно, мы можем доказать более интересные вещи, но это общая идея.
До сих пор мы имели дело с индуктивно определенными данными, которые мы получили, позволив им быть «наименьшим» набором. Итак, теперь мы хотим работать с кодированными кодами, которые мы получаем, позволяя получить самый большой набор.
Так
Позвольте быть набором. Набор «Поток a» определяется как наибольший набор, такой, что для каждого x в потоке a, x состоит из упорядоченной пары (голова, хвост), так что голова находится в a, а хвост находится в потоке a
В Хаскеле мы бы выразили это как
На самом деле, в Haskell мы обычно используем встроенные списки, которые могут быть упорядоченной парой или пустым списком.
Банан также не является членом этого типа, так как это не упорядоченная пара или пустой список. Но теперь мы можем сказать,
и это совершенно правильное определение. Более того, мы можем выполнить совместную рекурсию по этим данным. На самом деле, функция может быть одновременно и рекурсивной, и рекурсивной. В то время как рекурсия была определена функцией, имеющей домен, состоящий из данных, ко-рекурсия просто означает, что у нее есть совместная область (также называемая диапазоном), которая является совместной информацией. Примитивная рекурсия означала всегда «звонить самому себе» по меньшим данным до достижения самых маленьких данных. Примитивная совместная рекурсия всегда "вызывает себя" на данных, которые больше или равны тем, которые вы имели ранее.
примитивно ко-рекурсивный. В то время как функция
map
(вроде как «foreach» в императивных языках) является примитивно рекурсивной (как бы) и примитивно ко-рекурсивной.То же самое касается функции,
zipWith
которая берет функцию и пару списков и объединяет их вместе, используя эту функцию.классическим примером функциональных языков является последовательность Фибоначчи
который является примитивно рекурсивным, но может быть более элегантно выражен как бесконечный список
Интересным примером индукции / соиндукции является доказательство того, что эти два определения вычисляют одно и то же. Это оставлено в качестве упражнения для читателя.
источник
По сути, corecursion представляет собой аккумуляторный тип рекурсии , который строит свой результат на пути вперед от исходного случая, тогда как регулярная рекурсия строит свой результат на обратном пути от базового случая.
(говорит на Хаскеле сейчас). Вот почему
foldr
(со строгой функцией объединения) выражает рекурсию, иfoldl'
(со строгой комбинацией. F. ) /scanl
/until
/iterate
/unfoldr
/ И т. Д. Выражает corecursion. Corecursion есть везде.foldr
с не строгой расческой. е. выражает хвостовую рекурсию по модулю минусов .И защищенная рекурсия Хаскелла - это как хвостовая рекурсия по модулю минусов .
Это рекурсия:
(читается
$
как "из"). Это corecursion:Складки: http://en.wikipedia.org/wiki/Fold_(higher-order_function)
источник
Проверьте это в блоге Витомира Ковановича . Я нашел это в точку:
источник