Was ist der Unterschied zwischen diesen?
Auf Wikipedia gibt es nur wenige Informationen und keinen eindeutigen Code, der diese Begriffe erklärt.
Was sind einige sehr einfache Beispiele, die diese Begriffe erklären?
Wie ist Corecursion das Duale der Rekursion?
Gibt es klassische CoreCusive-Algorithmen?
algorithms
recursion
user167908
quelle
quelle
Antworten:
Es gibt eine Reihe guter Betrachtungsweisen. Für mich ist es am einfachsten, über die Beziehung zwischen "induktiven" und "koinduktiven Definitionen" nachzudenken.
Eine induktive Definition einer Menge geht so.
Die Menge "Nat" ist definiert als die kleinste Menge, so dass "Zero" in Nat ist, und wenn n in Nat ist, ist "Succ n" in Nat.
Welches entspricht der folgenden Ocaml
Eine Sache, die an dieser Definition zu beachten ist, ist die Zahl
ist KEIN Mitglied dieses Sets. Warum? Nehmen wir an, dass dies der Fall war, und betrachten Sie nun die Menge N, die dieselben Elemente wie Nat enthält, außer dass sie kein Omega enthält. Offensichtlich ist Null in N, und wenn y in N ist, ist Succ (y) in N, aber N ist kleiner als Nat, was ein Widerspruch ist. Also, Omega ist nicht in Nat.
Oder vielleicht nützlicher für einen Informatiker:
Wenn eine Menge "a" gegeben ist, wird die Menge "Liste von a" als die kleinste Menge definiert, so dass "Nil" in Liste von a ist und wenn xs in Liste von a ist und x in einem "Cons x xs" ist. ist in der Liste von a.
Was sowas entspricht
Das operative Wort ist hier "kleinste". Wenn wir nicht "kleinste" sagen würden, könnten wir nicht sagen, ob das Set Nat eine Banane enthält!
Nochmal,
ist keine gültige Definition für eine Liste von Nats, genau wie Omega keine gültige Nat war.
Induziertes Definieren von Daten auf diese Weise ermöglicht es uns, Funktionen zu definieren, die mithilfe von Rekursion darauf arbeiten
wir können dann Tatsachen darüber beweisen, wie "plus eine Null = a" durch Induktion (speziell strukturelle Induktion)
Unser Beweis erfolgt durch strukturelle Induktion auf a.
Für den Basisfall sei a Null.
plus Zero Zero = match Zero with |Zero -> Zero | Succ(c) -> let r = plus c b in Succ(r)
so wissen wir esplus Zero Zero = Zero
. Lassa
ein nat sein. Nehmen wir die induktive Hypothese an, dassplus a Zero = a
. Wir zeigen nun, dassplus (Succ(a)) Zero = Succ(a)
dies offensichtlich ist, daplus (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)
durch Induktionplus a Zero = a
für allea
in natWir können natürlich interessantere Dinge beweisen, aber das ist die allgemeine Idee.
Bisher haben wir uns mit induktiv definierten Daten befasst, die wir erhalten haben, indem wir sie zur "kleinsten" Menge gemacht haben. Nun wollen wir mit coinduktiv definierten Codaten arbeiten, die wir erhalten, indem wir sie zur größten Menge machen.
Damit
Sei a eine Menge. Die Menge "Stream of a" ist definiert als die größte Menge, so dass x für jedes x im Stream von a aus dem geordneten Paar (Kopf, Schwanz) besteht, sodass sich Kopf in a und Schwanz in Stream of a befindet
In Haskell würden wir dies ausdrücken als
Tatsächlich verwenden wir in Haskell normalerweise die eingebauten Listen, die ein geordnetes Paar oder eine leere Liste sein können.
Banana ist ebenfalls kein Mitglied dieses Typs, da es sich nicht um ein geordnetes Paar oder eine leere Liste handelt. Aber jetzt können wir sagen
und das ist eine vollkommen gültige Definition. Darüber hinaus können wir auf diesen Co-Daten eine Co-Rekursion durchführen. Tatsächlich ist es möglich, dass eine Funktion sowohl ko-rekursiv als auch rekursiv ist. Während Rekursion durch die Funktion definiert wurde, deren Domäne aus Daten besteht, bedeutet Ko-Rekursion nur, dass es sich bei der Ko-Domäne (auch als Bereich bezeichnet) um Ko-Daten handelt. Primitive Rekursion bedeutete, sich immer auf kleinere Daten zu "berufen", bis die kleinsten Daten erreicht waren. Primitive Co-Rekursion "ruft sich immer von selbst" auf Daten auf, die größer oder gleich dem sind, was Sie zuvor hatten.
ist primitiv ko-rekursiv. Während die Funktion
map
(wie "foreach" in imperativen Sprachen) sowohl primitiv rekursiv als auch primitiv ko-rekursiv ist.Gleiches gilt für die Funktion,
zipWith
die eine Funktion und ein Listenpaar aufnimmt und mit dieser Funktion zusammenfügt.Das klassische Beispiel für funktionale Sprachen ist die Fibonacci-Sequenz
Das ist primitiv rekursiv, kann aber eleganter als unendliche Liste ausgedrückt werden
Ein interessantes Beispiel für Induktion / Coinduktion beweist, dass diese beiden Definitionen dasselbe berechnen. Dies ist eine Übung für den Leser.
quelle
Grundsätzlich ist corecursion Rekursion Akkumulator-Stil , den Aufbau sein Ergebnisses auf dem Weg nach vorne aus dem Ausgangsfall, während der reguläre Rekursion sein Ergebnis auf dem Weg zurück vom baut Basisfall.
(spricht jetzt Haskell). Das ist der Grund, warum
foldr
(mit einer strengen Kombinationsfunktion) eine Rekursion ausdrückt undfoldl'
(mit einem strengen Kamm. F.) /scanl
/until
/iterate
/unfoldr
/ Usw. eine Kernkursion ausdrückt. Corecursion ist überall.foldr
mit nicht strengen Kamm. f. drückt die Schweifrekursion modulo cons aus .Und Haskells vorsichtige Rekursion ist genau wie die modulo Nachteile der Schwanzrekursion .
Das ist Rekursion:
(gelesen
$
als "von"). Das ist Corecursion:Falten: http://en.wikipedia.org/wiki/Fold_(higher-order_function)
quelle
Überprüfen Sie dies auf Vitomir Kovanovic 's Blog . Ich fand es auf den Punkt:
quelle