Ein Y-Kombinator ist ein Informatikkonzept von der „funktionalen“ Seite der Dinge. Die meisten Programmierer wissen überhaupt nicht viel über Kombinatoren, wenn sie überhaupt davon gehört haben.
- Was ist ein Y-Kombinator?
- Wie funktionieren Kombinatoren?
- Wofür sind sie gut?
- Sind sie in prozeduralen Sprachen nützlich?
functional-programming
computer-science
theory
definition
combinators
Chris Ammerman
quelle
quelle
Antworten:
Wenn Sie für eine lange Lektüre bereit sind, hat Mike Vanier eine gute Erklärung . Kurz gesagt, es ermöglicht Ihnen, die Rekursion in einer Sprache zu implementieren, die sie nicht unbedingt nativ unterstützt.
quelle
Ein Y-Kombinator ist eine "Funktion" (eine Funktion, die andere Funktionen ausführt), die eine Rekursion ermöglicht, wenn Sie nicht von selbst auf die Funktion verweisen können. In der Informatik-Theorie verallgemeinert sie die Rekursion , abstrahiert ihre Implementierung und trennt sie dadurch von der eigentlichen Arbeit der betreffenden Funktion. Der Vorteil, dass für die rekursive Funktion kein Name zur Kompilierungszeit benötigt wird, ist eine Art Bonus. =)
Dies gilt für Sprachen, die Lambda-Funktionen unterstützen . Die ausdrucksbasierte Natur von Lambdas bedeutet normalerweise, dass sie sich nicht namentlich auf sich selbst beziehen können. Und dies zu umgehen, indem man die Variable deklariert, auf sie verweist und ihr dann das Lambda zuweist, um die Selbstreferenzschleife zu vervollständigen, ist spröde. Die Lambda-Variable kann kopiert und die ursprüngliche Variable neu zugewiesen werden, wodurch die Selbstreferenz unterbrochen wird.
Y-Kombinatoren sind in statisch typisierten Sprachen (die häufig prozedurale Sprachen sind) umständlich zu implementieren und häufig zu verwenden, da für Typisierungsbeschränkungen normalerweise die Anzahl der Argumente für die betreffende Funktion zur Kompilierungszeit bekannt sein muss. Dies bedeutet, dass ein y-Kombinator für jede Argumentanzahl geschrieben werden muss, die verwendet werden muss.
Unten finden Sie ein Beispiel für die Verwendung und Funktionsweise eines Y-Kombinators in C #.
Die Verwendung eines Y-Kombinators beinhaltet eine "ungewöhnliche" Art der Konstruktion einer rekursiven Funktion. Zuerst müssen Sie Ihre Funktion als Code schreiben, der eine bereits vorhandene Funktion aufruft und nicht sich selbst:
Dann verwandeln Sie das in eine Funktion, die eine Funktion zum Aufrufen benötigt, und geben eine Funktion zurück, die dies tut. Dies wird als Funktion bezeichnet, da es eine Funktion übernimmt und damit eine Operation ausführt, die zu einer anderen Funktion führt.
Jetzt haben Sie eine Funktion, die eine Funktion übernimmt und eine andere Funktion zurückgibt, die wie eine Fakultät aussieht, aber anstatt sich selbst aufzurufen, ruft sie das an die äußere Funktion übergebene Argument auf. Wie macht man das zur Fakultät? Übergeben Sie die innere Funktion an sich selbst. Der Y-Kombinator tut dies, indem er eine Funktion mit einem permanenten Namen ist, die die Rekursion einführen kann.
Anstelle des faktoriellen Aufrufs selbst geschieht, dass der faktorielle Aufruf den faktoriellen Generator aufruft (der durch den rekursiven Aufruf an Y-Combinator zurückgegeben wird). Und abhängig vom aktuellen Wert von t ruft die vom Generator zurückgegebene Funktion den Generator entweder erneut mit t - 1 auf oder gibt nur 1 zurück, wodurch die Rekursion beendet wird.
Es ist kompliziert und kryptisch, aber zur Laufzeit wird alles durcheinander gebracht, und der Schlüssel zu seiner Arbeit ist die "verzögerte Ausführung" und das Aufbrechen der Rekursion, um zwei Funktionen zu umfassen. Das innere F wird als Argument übergeben , das in der nächsten Iteration nur bei Bedarf aufgerufen wird .
quelle
fix :: (a -> a) -> a
, und diea
Dose kann wiederum von so vielen Argumenten abhängen, wie Sie möchten. Dies bedeutet, dass statisches Tippen dies nicht wirklich umständlich macht.Ich habe dies von http://www.mail-archive.com/[email protected]/msg02716.html aufgehoben. Dies ist eine Erklärung, die ich vor einigen Jahren geschrieben habe.
In diesem Beispiel werde ich JavaScript verwenden, aber viele andere Sprachen funktionieren auch.
Unser Ziel ist es, eine rekursive Funktion von 1 Variablen zu schreiben, indem wir nur Funktionen von 1 Variablen und keine Zuweisungen verwenden, Dinge nach Namen definieren usw. (Warum dies unser Ziel ist, ist eine andere Frage, nehmen wir dies einfach als die Herausforderung, die wir stellen werden gegeben.) Scheint unmöglich, nicht wahr? Lassen Sie uns als Beispiel Fakultät implementieren.
Nun, Schritt 1 ist zu sagen, dass wir dies leicht tun könnten, wenn wir ein wenig schummeln würden. Mit Funktionen von 2 Variablen und Zuweisung können wir zumindest vermeiden, dass die Zuordnung zum Einrichten der Rekursion verwendet werden muss.
Nun wollen wir sehen, ob wir weniger schummeln können. Zunächst verwenden wir die Zuweisung, müssen dies aber nicht. Wir können einfach X und Y inline schreiben.
Wir verwenden jedoch Funktionen von 2 Variablen, um eine Funktion von 1 Variablen zu erhalten. Können wir das beheben? Nun, ein kluger Kerl namens Haskell Curry hat einen ordentlichen Trick. Wenn Sie gute Funktionen höherer Ordnung haben, brauchen Sie nur Funktionen von 1 Variablen. Der Beweis ist, dass Sie mit einer rein mechanischen Texttransformation wie dieser von Funktionen von 2 (oder im allgemeinen Fall mehr) Variablen zu 1 Variablen gelangen können:
wo ... bleibt genau das gleiche. (Dieser Trick wird nach seinem Erfinder "Currying" genannt. Die Sprache Haskell wird auch nach Haskell Curry benannt. Datei unter nutzlosen Trivia.) Wenden Sie diese Transformation jetzt einfach überall an und wir erhalten unsere endgültige Version.
Fühlen Sie sich frei, es zu versuchen. alert (), die zurückkehren, binden Sie es an einen Knopf, was auch immer. Dieser Code berechnet Fakultäten rekursiv ohne Verwendung von Zuweisungen, Deklarationen oder Funktionen von 2 Variablen. (Wenn Sie jedoch nachverfolgen, wie es funktioniert, dreht sich wahrscheinlich der Kopf. Wenn Sie es ohne Ableitung nur leicht neu formatieren, wird der Code zu einem Code, der Sie verwirren und verwirren wird.)
Sie können die 4 Zeilen, die die Fakultät rekursiv definieren, durch jede andere gewünschte rekursive Funktion ersetzen.
quelle
function (n) { return builder(builder)(n);}
statt geschriebenbuilder(builder)
?Ich frage mich, ob es sinnvoll ist, dies von Grund auf aufzubauen. Wir werden sehen. Hier ist eine grundlegende, rekursive Fakultätsfunktion:
Lassen Sie uns eine neue Funktion namens umgestalten und erstellen
fact
, die eine anonyme Fakultätsberechnungsfunktion zurückgibt, anstatt die Berechnung selbst durchzuführen:Das ist ein bisschen komisch, aber daran ist nichts auszusetzen. Wir generieren nur bei jedem Schritt eine neue Fakultätsfunktion.
Die Rekursion in dieser Phase ist noch ziemlich explizit. Die
fact
Funktion muss ihren eigenen Namen kennen. Lassen Sie uns den rekursiven Aufruf parametrisieren:Das ist toll, muss aber
recurser
noch seinen eigenen Namen kennen. Lassen Sie uns auch das parametrisieren:Anstatt
recurser(recurser)
direkt aufzurufen , erstellen wir jetzt eine Wrapper-Funktion, die das Ergebnis zurückgibt:Wir können jetzt die loswerden
recurser
Namen insgesamt ; Es ist nur ein Argument für Ys innere Funktion, die durch die Funktion selbst ersetzt werden kann:Der einzige externe Name, auf den noch verwiesen wird
fact
, ist , aber es sollte inzwischen klar sein, dass auch dieser leicht zu parametrisieren ist, um die vollständige, generische Lösung zu erstellen:quelle
recurser
. Nicht die geringste Ahnung, was es tut oder warum.recurser
Funktion ist der erste Schritt in Richtung dieses Ziels, da sie uns eine rekursive Version gibt,fact
die sich niemals namentlich referenziert.function Y(recurse) { return recurse(recurse); } let factorial = Y(creator => value => { return value == 0 ? 1 : value * creator(creator)(value - 1); });
. Und so verdaue ich es (nicht sicher, ob es korrekt ist): Indem wir die Funktion nicht explizit referenzieren (als Kombinator nicht zulässig ), können wir zwei teilweise angewendete / Curry- Funktionen (eine Erstellerfunktion und die Berechnungsfunktion) mit verwenden Mit welchen Lambda / anonymen Funktionen können wir rekursiv arbeiten, ohne dass ein Name für die Berechnungsfunktion erforderlich ist?Die meisten Antworten oben beschreiben , was der Y-Combinator ist aber nicht das, was es ist für .
Festpunkt combinators werden verwendet um zu zeigen , dass Lambda - Kalkül ist Turing vollständig . Dies ist ein sehr wichtiges Ergebnis in der Berechnungstheorie und bietet eine theoretische Grundlage für die funktionale Programmierung .
Das Studium von Festkomma-Kombinatoren hat mir auch geholfen, die funktionale Programmierung wirklich zu verstehen. Ich habe jedoch nie eine Verwendung für sie in der tatsächlichen Programmierung gefunden.
quelle
y-Kombinator in JavaScript :
Bearbeiten : Ich lerne viel aus dem Betrachten von Code, aber dieser ist ohne Hintergrund etwas schwer zu schlucken - tut mir leid. Mit einigen allgemeinen Kenntnissen, die durch andere Antworten vermittelt werden, können Sie beginnen, herauszufinden, was gerade passiert.
Die Y-Funktion ist der "y-Kombinator". Schauen Sie sich nun die
var factorial
Zeile an, in der Y verwendet wird. Beachten Sie, dass Sie eine Funktion übergeben, die einen Parameter (in diesem Beispielrecurse
) enthält, der später auch in der inneren Funktion verwendet wird. Der Parametername wird im Grunde genommen zum Namen der inneren Funktion, die es ihr ermöglicht, einen rekursiven Aufruf auszuführen (da errecurse()
in seiner Definition verwendet wird). Der y-Kombinator führt die Magie aus, die ansonsten anonyme innere Funktion mit dem Parameternamen der übergebenen Funktion zu verknüpfen Y. Y.Die vollständige Erklärung, wie Y die Magie ausübt , finden Sie in dem verlinkten Artikel (übrigens nicht von mir).
quelle
arguments.callee
ist im strengen Modus nicht erlaubt: developer.mozilla.org/en/JavaScript/…(function fact(n){ return n <= 1? 1 : n * fact(n-1); })(5)
Für Programmierer, die noch nicht in der Tiefe auf funktionale Programmierung gestoßen sind und jetzt nicht anfangen möchten, aber leicht neugierig sind:
Der Y-Kombinator ist eine Formel, mit der Sie die Rekursion in einer Situation implementieren können, in der Funktionen keine Namen haben können, sondern als Argumente weitergegeben, als Rückgabewerte verwendet und in anderen Funktionen definiert werden können.
Es funktioniert, indem die Funktion als Argument an sich selbst übergeben wird, damit sie sich selbst aufrufen kann.
Es ist Teil des Lambda-Kalküls, das eigentlich Mathematik ist, aber effektiv eine Programmiersprache ist und für die Informatik und insbesondere für die funktionale Programmierung ziemlich grundlegend ist.
Der tägliche praktische Wert des Y-Kombinators ist begrenzt, da Programmiersprachen dazu neigen, Funktionen zu benennen.
Falls Sie es in einer Polizeiaufstellung identifizieren müssen, sieht es folgendermaßen aus:
Sie können es normalerweise wegen der wiederholten erkennen
(λx.f (x x))
.Die
λ
Symbole sind der griechische Buchstabe Lambda, der dem Lambda-Kalkül seinen Namen gibt, und es gibt viele(λx.t)
Stilbegriffe, weil der Lambda-Kalkül so aussieht.quelle
U x = x x
,Y = U . (. U)
(missbrauchen Haskell-artige Notation). IOW, mit geeigneten Kombinatoren ,Y = BU(CBU)
. Also ,Yf = U (f . U) = (f . U) (f . U) = f (U (f . U)) = f ((f . U) (f . U))
.Anonyme Rekursion
Ein Festkommakombinator ist eine Funktion höherer Ordnung
fix
, die per Definition die Äquivalenz erfülltfix f
stellt eine Lösungx
für die Festpunktgleichung darDie Fakultät einer natürlichen Zahl kann durch bewiesen werden
Unter Verwendung
fix
beliebiger konstruktiver Beweise über allgemeine / μ-rekursive Funktionen können ohne nonymöse Selbstreferenzialität abgeleitet werden.wo
so dass
Dieser formale Beweis dafür
Verwendet methodisch die Äquivalenz des Festkomma-Kombinators für das Umschreiben
Lambda-Kalkül
Der untypisierte Lambda-Kalkül- Formalismus besteht aus einer kontextfreien Grammatik
wo
v
erstreckt sich über Variablen zusammen mit den Beta und eta Reduktion RegelnDie Beta-Reduktion ersetzt alle freien Vorkommen der Variablen
x
im Abstraktionskörper ("Funktion")B
durch den Ausdruck ("Argument")E
. Eta-Reduktion eliminiert redundante Abstraktion. Es wird manchmal aus dem Formalismus weggelassen. Ein irreduzibler Ausdruck, für den keine Reduktionsregel gilt, liegt in normaler oder kanonischer Form vor .ist eine Abkürzung für
(Abstraktionsmultiarität),
ist eine Abkürzung für
(Anwendung Linksassoziativität),
und
sind Alpha-Äquivalent .
Abstraktion und Anwendung sind die beiden einzigen „Sprachprimitive“ des Lambda-Kalküls, ermöglichen jedoch die Codierung beliebig komplexer Daten und Operationen.
Die Kirchenzahlen sind eine Kodierung der natürlichen Zahlen, die den peanoaxiomatischen Naturzahlen ähnlich sind.
Ein formeller Beweis dafür
Verwenden der Umschreiberegel der Beta-Reduzierung:
Kombinatoren
In der Lambda-Rechnung sind Kombinatoren Abstraktionen, die keine freien Variablen enthalten. Am einfachsten:
I
der Identitätskombinatorisomorph zur Identitätsfunktion
Solche Kombinatoren sind die primitiven Operatoren von Kombinatorkalkülen wie dem SKI-System.
Die Beta-Reduktion normalisiert sich nicht stark . Nicht alle reduzierbaren Ausdrücke, „Redexes“, konvergieren unter Beta-Reduktion zur normalen Form. Ein einfaches Beispiel ist die unterschiedliche Anwendung des Omega-
ω
Kombinatorszu sich selbst:
Die Reduzierung der am weitesten links stehenden Unterausdrücke („Köpfe“) wird priorisiert. Die anwendbare Reihenfolge normalisiert die Argumente vor der Substitution, die normale Reihenfolge nicht. Die beiden Strategien sind analog zu eifriger Bewertung, z. B. C, und fauler Bewertung, z. B. Haskell.
divergiert unter eifriger Beta-Reduktion in der Anwendungsreihenfolge
da in strengen Semantik
konvergiert aber unter fauler Beta-Reduktion normaler Ordnung
Wenn ein Ausdruck eine normale Form hat, wird er durch eine Beta-Reduktion normaler Ordnung gefunden.
Y.
Die wesentliche Eigenschaft des
Y
Festkommakombinatorsist gegeben durch
Die Äquivalenz
ist isomorph zu
Der untypisierte Lambda-Kalkül kann beliebige konstruktive Beweise über allgemeine / μ-rekursive Funktionen codieren.
(Multiplikation verzögert, Zusammenfluss)
Für den kirchlichen untypisierten Lambda-Kalkül wurde gezeigt, dass es außerdem eine rekursiv aufzählbare Unendlichkeit von Festpunktkombinatoren gibt
Y
.Die Beta-Reduktion normaler Ordnung macht den nicht erweiterten untypisierten Lambda-Kalkül zu einem Turing-vollständigen Umschreibungssystem.
In Haskell kann der Festkomma-Kombinator elegant implementiert werden
Haskells Faulheit normalisiert sich auf eine Endlichkeit, bevor alle Unterausdrücke ausgewertet wurden.
quelle
λ x . x
, wie geht es dir heute?Andere Antworten geben eine ziemlich präzise Antwort darauf, ohne eine wichtige Tatsache: Sie müssen den Festkomma-Kombinator auf diese verschlungene Weise in keiner praktischen Sprache implementieren und dies dient keinem praktischen Zweck (außer "Schau, ich weiß, welcher Y-Kombinator" ist "). Es ist ein wichtiges theoretisches Konzept, aber von geringem praktischem Wert.
quelle
Hier ist eine JavaScript-Implementierung des Y-Kombinators und der Factorial-Funktion (aus Douglas Crockfords Artikel, verfügbar unter: http://javascript.crockford.com/little.html ).
quelle
Ein Y-Kombinator ist ein anderer Name für einen Flusskondensator.
quelle
Ich habe sowohl in Clojure als auch in Scheme eine Art "Idioten-Leitfaden" für den Y-Kombinator geschrieben, um mich damit auseinanderzusetzen. Sie sind beeinflusst von Material in "The Little Schemer"
Im Schema: https://gist.github.com/z5h/238891
oder Clojure: https://gist.github.com/z5h/5102747
Beide Tutorials sind Code mit Kommentaren durchsetzt und sollten ausgeschnitten und in Ihren Lieblingseditor eingefügt werden können.
quelle
Als Neuling in Kombinatoren fand ich Mike Vaniers Artikel (danke Nicholas Mancuso) sehr hilfreich. Ich möchte neben der Dokumentation meines Verständnisses eine Zusammenfassung schreiben, wenn es einigen anderen helfen könnte, wäre ich sehr froh.
Von beschissen zu weniger beschissen
Am Beispiel der Fakultät verwenden wir die folgende
almost-factorial
Funktion, um die Fakultät der Zahl zu berechnenx
:Nimmt
almost-factorial
im obigen Pseudocode Funktionf
und Zahl aufx
(almost-factorial
wird als Curry verwendet, so dass es als Aufnahme von Funktionf
und Rückgabe einer 1-Aritätsfunktion angesehen werden kann).Wenn
almost-factorial
berechnet für factorialx
es die Berechnung der faktoriellen Delegiertenx - 1
zu Funktionf
und reichert sich dieses Ergebnis mitx
(in diesem Fall multipliziert es das Ergebnis von (x - 1) mit x).Es kann so gesehen werden, dass es
almost-factorial
eine beschissene Version der Fakultätsfunktion (die nur die Kassenzahl berechnen kannx - 1
) aufnimmt und eine weniger beschissene Version der Fakultät zurückgibt (die die Kassenzahl berechnetx
). Wie in dieser Form:Wenn wir die weniger beschissene Version von Fakultät wiederholt an übergeben
almost-factorial
, erhalten wir schließlich unsere gewünschte Fakultätsfunktionf
. Wo es betrachtet werden kann als:Fixpunkt
Die Tatsache, die
almost-factorial f = f
bedeutet,f
ist der Fixpunkt der Funktionalmost-factorial
.Dies war eine wirklich interessante Art, die Beziehungen der oben genannten Funktionen zu sehen, und es war ein Aha-Moment für mich. (Bitte lesen Sie Mikes Beitrag zum Fixpunkt, wenn Sie dies nicht getan haben.)
Drei Funktionen
Zu verallgemeinern, wir haben nicht-rekursive Funktion
fn
(wie unsere fast-Fakultät), haben wir seine Fix-Punkt - Funktionfr
(wie unser f), was dannY
tut , ist , wenn Sie gebenY
fn
,Y
gibt die Fix-Punkt - Funktionfn
.Zusammenfassend (vereinfacht durch die Annahme, dass
fr
nur ein Parameter benötigt wird;x
degeneriert zux - 1
,x - 2
... in Rekursion):fn
:def fn fr x = ...accumulate x with result from (fr (- x 1))
, Dies ist die fast nützliche Funktion - obwohl wir sie nichtfn
direkt verwenden könnenx
, wird sie sehr bald nützlich sein. Dies ist nicht rekursivfn
Funktion verwendet eine Funktionfr
, um das Ergebnis zu berechnenfn fr = fr
,fr
Ist der Fix-Punktfn
,fr
ist die nützliche funciton, können wir verwendenfr
aufx
unser Ergebnis zu erhaltenY fn = fr
,Y
gibt den Fixpunkt einer Funktion zurück undY
verwandelt unsere fast nützliche Funktionfn
in nützlichfr
Ableiten
Y
(nicht enthalten)Ich werde die Ableitung von überspringen
Y
und zum Verständnis gehenY
. Mike Vainers Beitrag enthält viele Details.Die Form von
Y
Y
ist definiert als (im Lambda-Kalkül- Format):Wenn wir die Variable
s
links von den Funktionen ersetzen , erhalten wirDas Ergebnis von
(Y f)
ist in der Tat der Fixpunkt vonf
.Warum
(Y f)
arbeitet?Abhängig von der Signatur von
f
,(Y f)
kann eine Funktion jeder Arität sein. Nehmen wir zur Vereinfachung an, dass(Y f)
nur ein Parameter verwendet wird, wie unsere Fakultätsfunktion.da machen
fn fr = fr
wir weiterDie rekursive Berechnung wird beendet, wenn das Innerste
(fn fr 1)
der Basisfall ist undfn
nichtfr
in der Berechnung verwendet wird.Nochmal
Y
anschauen:Damit
Für mich sind die magischen Teile dieses Setups:
fn
undfr
voneinander abhängig:fr
'Wraps' imfn
Inneren, jedes Mal, wennfr
es zum Berechnen verwendet wirdx
, 'spawnt' es ('hebt'?)fn
und delegiert die Berechnung an diesesfn
(in sich selbstfr
undx
). Auf der anderen Seitefn
hängt davon abfr
und verwendetfr
, um das Ergebnis eines kleineren Problems zu berechnenx-1
.fr
wird verwendet , um zu definierenfn
(beifn
Verwendungenfr
in seinen Operationen), die realenfr
sind noch nicht definiert.fn
was die eigentliche Geschäftslogik definiert. Basierend auffn
,Y
schafftfr
- eine Hilfsfunktion in einer bestimmten Form - die Berechnung zu erleichternfn
in einer rekursiven Weise.Es hat mir
Y
im Moment geholfen, diesen Weg zu verstehen , hoffe es hilft.Übrigens fand ich das Buch Eine Einführung in die funktionale Programmierung durch Lambda-Kalkül auch sehr gut, ich bin nur ein Teil davon und die Tatsache, dass ich
Y
mich in dem Buch nicht zurechtfinden konnte, führte mich zu diesem Beitrag.quelle
Hier finden Sie Antworten auf die ursprünglichen Fragen , die aus dem Artikel zusammengestellt wurden (der VOLLSTÄNDIG lesenswert ist), der in der Antwort von Nicholas Mancuso erwähnt wurde , sowie weitere Antworten:
Ein Y-Kombinator ist eine "Funktion" (oder eine Funktion höherer Ordnung - eine Funktion, die mit anderen Funktionen arbeitet), die ein einzelnes Argument verwendet, eine Funktion, die nicht rekursiv ist, und eine Version der Funktion zurückgibt rekursiv.
Etwas rekursiv =), aber detaillierter definiert:
Ein Kombinator - ist nur ein Lambda-Ausdruck ohne freie Variablen.
Freie Variable - ist eine Variable, die keine gebundene Variable ist.
Gebundene Variable - Variable, die im Hauptteil eines Lambda-Ausdrucks enthalten ist, dessen Variablenname eines seiner Argumente ist.
Eine andere Möglichkeit, darüber nachzudenken, besteht darin, dass der Kombinator ein solcher Lambda-Ausdruck ist, bei dem Sie den Namen eines Kombinators überall dort, wo er gefunden wird, durch seine Definition ersetzen können und alles noch funktioniert (Sie werden in eine Endlosschleife geraten, wenn der Kombinator dies tun würde Verweis auf sich selbst enthalten, innerhalb des Lambda-Körpers).
Der Y-Kombinator ist ein Festpunktkombinator.
Der Fixpunkt einer Funktion ist ein Element der Funktionsdomäne, das von der Funktion auf sich selbst abgebildet wird.
Das heißt,
c
ist ein fester Punkt der Funktion,f(x)
wennf(c) = c
dies bedeutet
f(f(...f(c)...)) = fn(c) = c
Die folgenden Beispiele setzen eine starke + dynamische Typisierung voraus :
Fauler Y-Kombinator (normaler Ordnung):
Diese Definition gilt für Sprachen mit fauler (auch: verzögerter, bedarfsgerechter) Bewertung - Bewertungsstrategie, die die Bewertung eines Ausdrucks verzögert, bis sein Wert benötigt wird.
Dies bedeutet, dass für eine gegebene Funktion
f
(die eine nicht rekursive Funktion ist) die entsprechende rekursive Funktion zuerst erhalten werden kannλx.f(x x)
, indem dieser Lambda-Ausdruck berechnet und dann auf sich selbst angewendet wird .Strenger Y-Kombinator (Anwendungsreihenfolge):
Diese Definition gilt für Sprachen mit strenger (auch: eifriger, gieriger) Bewertung - Bewertungsstrategie, bei der ein Ausdruck bewertet wird, sobald er an eine Variable gebunden ist.
Es ist das gleiche wie faul in seiner Natur, es hat nur eine zusätzliche
λ
Hülle, um die Körperbewertung des Lambda zu verzögern. Ich habe eine andere Frage gestellt , die etwas mit diesem Thema zu tun hat.Stolenentlehnt Antwort von Chris Ammerman : Y-Combinator generalizes Rekursion, deren Umsetzungabstrahieren, und damit es von der eigentlichen Arbeit der Funktion in Fragetrennen.Obwohl der Y-Kombinator einige praktische Anwendungen hat, handelt es sich hauptsächlich um ein theoretisches Konzept, dessen Verständnis Ihre Gesamtvision erweitert und wahrscheinlich Ihre Analyse- und Entwicklerfähigkeiten verbessert.
Wie von Mike Vanier angegeben : Es ist möglich, einen Y-Kombinator in vielen statisch typisierten Sprachen zu definieren, aber (zumindest in den Beispielen, die ich gesehen habe) erfordern solche Definitionen normalerweise einen nicht offensichtlichen Typ-Hackery, da der Y-Kombinator selbst dies nicht tut. t haben einen einfachen statischen Typ. Das geht über den Rahmen dieses Artikels hinaus, daher werde ich es nicht weiter erwähnen
Und wie von Chris Ammerman erwähnt : Die meisten prozeduralen Sprachen haben statische Typisierung.
Also antworte auf diese Frage - nicht wirklich.
quelle
Der y-Kombinator implementiert eine anonyme Rekursion. Also statt
du kannst tun
Natürlich funktioniert der y-Kombinator nur in Call-by-Name-Sprachen. Wenn Sie dies in einer normalen Call-by-Value-Sprache verwenden möchten, benötigen Sie den zugehörigen Z-Kombinator (der Y-Kombinator divergiert / Endlosschleife).
quelle
Ein Festkomma-Kombinator (oder Festkomma-Operator) ist eine Funktion höherer Ordnung, die einen Festpunkt anderer Funktionen berechnet. Diese Operation ist in der Programmiersprachentheorie relevant, da sie die Implementierung einer Rekursion in Form einer Umschreiberegel ohne explizite Unterstützung durch die Laufzeit-Engine der Sprache ermöglicht. (src Wikipedia)
quelle
Der this-Operator kann Ihr Leben vereinfachen:
Dann vermeiden Sie die Zusatzfunktion:
Schließlich rufen Sie an
fac(5)
.quelle
Ich denke, der beste Weg, dies zu beantworten, ist die Auswahl einer Sprache wie JavaScript:
Schreiben Sie es jetzt so um, dass es nicht den Namen der Funktion innerhalb der Funktion verwendet, sondern es dennoch rekursiv aufruft.
Der einzige Ort, an dem der Funktionsname angezeigt werden
factorial
sollte, ist die Aufrufstelle.Hinweis: Sie können keine Namen von Funktionen verwenden, aber Sie können Namen von Parametern verwenden.
Arbeiten Sie das Problem. Schau nicht nach. Sobald Sie es gelöst haben, werden Sie verstehen, welches Problem der y-Kombinator löst.
quelle