Jaka jest różnica między nimi?
Na Wikipedii jest niewiele informacji i brak wyraźnego kodu wyjaśniającego te warunki.
Jakie są bardzo proste przykłady wyjaśniające te terminy?
W jaki sposób corecursion jest podwójny względem rekurencji?
Czy są jakieś klasyczne algorytmy rdzeniowe?
algorithms
recursion
użytkownik167908
źródło
źródło
Odpowiedzi:
Jest na to wiele dobrych sposobów. Najłatwiej jest mi pomyśleć o związku między „indukcyjnymi” a „koindukcyjnymi definicjami”
Indukcyjna definicja zestawu wygląda następująco.
Zbiór „Nat” jest zdefiniowany jako najmniejszy zbiór, tak że „Zero” jest w Nat, a jeśli n jest w Nat, „Succ” jest w Nat.
Co odpowiada następującemu Ocamlowi
Należy zwrócić uwagę na tę definicję, że liczba
NIE jest członkiem tego zestawu. Dlaczego? Załóżmy, że tak było, rozważmy teraz zestaw N, który ma wszystkie te same elementy co Nat, z wyjątkiem tego, że nie ma omegi. Wyraźnie zero jest w N, a jeśli y jest w N, Succ (y) jest w N, ale N jest mniejsze niż Nat, co jest sprzecznością. Omegi nie ma w Nat.
Lub może bardziej przydatny dla informatyka:
Biorąc pod uwagę pewien zestaw „a”, zestaw „Lista a” jest zdefiniowany jako najmniejszy zbiór, taki że „zero” znajduje się na liście a, a jeśli xs jest na liście a, a x jest w „Cons x xs” jest na liście.
Co odpowiada coś takiego
Słowo operacyjne jest tutaj „najmniejsze”. Gdybyśmy nie powiedzieli „najmniejszy”, nie mielibyśmy żadnego sposobu na stwierdzenie, czy zestaw Nat zawiera banana!
Jeszcze raz,
nie jest poprawną definicją listy natów, tak jak omega nie była prawidłową Nat.
Definiowanie danych indukcyjnie w ten sposób pozwala nam definiować funkcje, które działają na nich za pomocą rekurencji
możemy następnie udowodnić fakty na ten temat, takie jak „plus zero = a” za pomocą indukcji (konkretnie indukcji strukturalnej)
Nasz dowód opiera się na indukcji strukturalnej na.
Dla przypadku podstawowego niech będzie zero.
plus Zero Zero = match Zero with |Zero -> Zero | Succ(c) -> let r = plus c b in Succ(r)
więc wiemyplus Zero Zero = Zero
. Niecha
będzie nat. Załóżmy hipotezę indukcyjną, żeplus a Zero = a
. Pokazujemy teraz, żeplus (Succ(a)) Zero = Succ(a)
jest to oczywiste, ponieważ wplus (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)
ten sposób przez indukcjęplus a Zero = a
dla wszystkicha
w natMożemy oczywiście udowodnić bardziej interesujące rzeczy, ale taka jest ogólna idea.
Do tej pory zajmowaliśmy się danymi zdefiniowanymi indukcyjnie, które otrzymaliśmy, pozwalając, aby był to „najmniejszy” zestaw. Więc teraz chcemy pracować z kododami zdefiniowanymi we współpracy, które otrzymujemy, pozwalając, aby był to największy zestaw.
Więc
Niech będzie zbiorem. Zbiór „Strumień a” jest zdefiniowany jako największy zbiór taki, że dla każdego xw strumieniu a x składa się z uporządkowanej pary (głowa, ogon) tak, że głowa jest w a, a ogon jest w strumieniu
W Haskell wyrazilibyśmy to jako
Właściwie w Haskell normalnie używamy wbudowanych list, które mogą być uporządkowaną parą lub pustą listą.
Banan też nie jest członkiem tego typu, ponieważ nie jest to uporządkowana para ani pusta lista. Ale teraz możemy powiedzieć
i jest to całkowicie poprawna definicja. Co więcej, możemy wykonywać rekurencję na tych współdanych. W rzeczywistości funkcja może być jednocześnie rekurencyjna i rekurencyjna. Podczas gdy rekurencja została zdefiniowana przez funkcję posiadającą domenę składającą się z danych, ko-rekurencja oznacza po prostu, że ma wspólną domenę (zwaną także zakresem), która jest współdanymi. Prymitywna rekurencja oznaczała zawsze „dzwonienie do siebie” na mniejszych danych, aż do osiągnięcia najmniejszych danych. Pierwotna ko-rekurencja zawsze „nazywa się” danymi większymi lub równymi temu, co posiadałeś wcześniej.
jest pierwotnie ko-rekurencyjny. Podczas gdy funkcja
map
(rodzaj „foreach” w imperatywnych językach) jest zarówno pierwotnie rekurencyjna (niejako), jak i pierwotnie ko-rekurencyjna.to samo dotyczy funkcji,
zipWith
która pobiera funkcję i parę list i łączy je ze sobą za pomocą tej funkcji.klasycznym przykładem języków funkcjonalnych jest sekwencja Fibonacciego
który jest pierwotnie rekurencyjny, ale można go wyrazić bardziej elegancko jako nieskończoną listę
Interesującym przykładem indukcji / koindukcji jest udowadnianie, że te dwie definicje obliczają to samo. Pozostaje to jako ćwiczenie dla czytelnika.
źródło
Zasadniczo, corecursion jest akumulatorem rekurencyjnym , budując swój wynik w drodze do przodu od przypadku początkowego, podczas gdy regularna rekurencja buduje swój wynik w drodze powrotnej z przypadku podstawowego.
(mówi teraz Haskell). Dlatego
foldr
(przy ścisłej funkcji łączenia) wyraża rekurencję ifoldl'
(przy ścisłym połączeniu. F.) /scanl
/until
/iterate
/unfoldr
/ Itd. Wyraża korektę. Corecursion jest wszędzie.foldr
z nieostrym grzebieniem. fa. wyraża wady modulo ogona rekurencyjnego .A strzeżona rekurencja Haskella jest jak wady modulo rekurencji ogona .
To jest rekurencja:
(czytaj
$
jako „z”). To jest sedno:Fałdy: http://en.wikipedia.org/wiki/Fold_(higher-order_function)
źródło
Sprawdź to na blogu Vitomir Kovanovic . Znalazłem to do rzeczy:
źródło