Ich verstehe nicht, was "Heben" ist. Sollte ich zuerst Monaden verstehen, bevor ich verstehe, was ein "Aufzug" ist? (Ich bin auch völlig unwissend über Monaden :) Oder kann mir jemand das mit einfachen Worten erklären?
haskell
functional-programming
GabiMe
quelle
quelle
Antworten:
Das Heben ist eher ein Entwurfsmuster als ein mathematisches Konzept (obwohl ich erwarte, dass mich hier jemand widerlegt, indem er zeigt, wie Aufzüge eine Kategorie oder etwas sind).
Normalerweise haben Sie einen Datentyp mit einem Parameter. Etwas wie
Angenommen , Sie feststellen , dass viele Anwendungen von
Foo
numerischen Typen nehmen (Int
,Double
usw.) und Sie halten, die zu schreiben Code, der diese Zahlen auspackt, ergänzt oder vervielfacht sie, und dann wickelt sie sichern. Sie können dies kurzschließen, indem Sie den Unwrap-and-Wrap-Code einmal schreiben. Diese Funktion wird traditionell als "Aufzug" bezeichnet, da sie folgendermaßen aussieht:Mit anderen Worten, Sie haben eine Funktion, die eine Funktion mit zwei Argumenten (z. B. den
(+)
Operator) in die entsprechende Funktion für Foos umwandelt.Jetzt können Sie also schreiben
Bearbeiten: Weitere Informationen
Sie können natürlich haben
liftFoo3
,liftFoo4
und so weiter. Dies ist jedoch häufig nicht erforderlich.Beginnen Sie mit der Beobachtung
Aber das ist genau das gleiche wie
fmap
. Also eher alsliftFoo1
du schreiben würdestWenn Sie wirklich vollständige Regelmäßigkeit wollen, können Sie sagen
Wenn Sie
Foo
einen Funktor machen können, können Sie ihn vielleicht zu einem anwendbaren Funktor machen. Wenn Sie schreiben können,liftFoo2
sieht die anwendbare Instanz tatsächlich so aus :Der
(<*>)
Operator für Foo hat den TypEs wendet die umschlossene Funktion auf den umschlossenen Wert an. Wenn Sie also implementieren
liftFoo2
können, können Sie dies in Bezug darauf schreiben. Oder Sie können es direkt implementieren und sich nicht darum kümmernliftFoo2
, da dasControl.Applicative
Modul enthältund ebenso gibt es
liftA
undliftA3
. Sie werden jedoch nicht sehr oft verwendet, da es einen anderen Operator gibtSo können Sie schreiben:
Der Begriff
myFunction <$> arg1
gibt eine neue Funktion zurück, die in Foo eingeschlossen ist. Dies kann wiederum auf das nächste Argument angewendet werden, indem(<*>)
usw. verwendet wird. Anstatt jetzt eine Liftfunktion für jede Arität zu haben, haben Sie nur noch eine Reihe von Anwendungen.quelle
lift id == id
undlift (f . g) == (lift f) . (lift g)
.id
und.
sind der Identitätspfeil und die Pfeilzusammensetzung einer Kategorie. Wenn Sie von Haskell sprechen, ist die fragliche Kategorie normalerweise "Hask", dessen Pfeile Haskell-Funktionen sind (mit anderen Worten,id
und.
beziehen sich auf die Haskell-Funktionen, die Sie kennen und lieben).instance Functor Foo
, nichtinstance Foo Functor
, nicht wahr? Ich würde mich selbst bearbeiten, bin mir aber nicht 100% sicher.Pauls und Yairchus sind beide gute Erklärungen.
Ich möchte hinzufügen, dass die Funktion, die aufgehoben wird, eine beliebige Anzahl von Argumenten haben kann und dass sie nicht vom gleichen Typ sein müssen. Sie können beispielsweise auch einen liftFoo1 definieren:
Im Allgemeinen wird das Heben von Funktionen, die 1 Argument annehmen, in der Typklasse erfasst
Functor
, und die Hebeoperation wird aufgerufenfmap
:Beachten Sie die Ähnlichkeit mit
liftFoo1
dem Typ. In der Tat können Sie, wenn Sie habenliftFoo1
,Foo
eine Instanz von erstellenFunctor
:Darüber hinaus wird die Verallgemeinerung des Aufhebens auf eine beliebige Anzahl von Argumenten als Anwendungsstil bezeichnet . Tauchen Sie erst ein, wenn Sie das Aufheben von Funktionen mit einer festen Anzahl von Argumenten verstanden haben. Aber wenn Sie dies tun, hat Learn you a Haskell ein gutes Kapitel dazu. Die Typeclassopedia ist ein weiteres gutes Dokument, das Functor und Applicative beschreibt (sowie andere Typklassen; scrollen Sie zum rechten Kapitel in diesem Dokument).
Hoffe das hilft!
quelle
Beginnen wir mit einem Beispiel (für eine übersichtlichere Darstellung wird ein Leerraum hinzugefügt):
liftA2
wandelt eine Funktion einfacher Typen in eine Funktion derselben Typen um, die in eine eingeschlossen sindApplicative
, z. B. ListenIO
usw.Ein weiterer üblicher Aufzug ist
lift
vonControl.Monad.Trans
. Es wandelt eine monadische Handlung einer Monade in eine Handlung einer transformierten Monade um.Im Allgemeinen hebt "lift" eine Funktion / Aktion in einen "Wrapped" -Typ um (damit die ursprüngliche Funktion "under the Wraps" funktioniert).
Der beste Weg, dies und Monaden usw. zu verstehen und zu verstehen, warum sie nützlich sind, besteht wahrscheinlich darin, sie zu codieren und zu verwenden. Wenn Sie zuvor etwas codiert haben, von dem Sie vermuten, dass es davon profitieren kann (dh der Code wird dadurch kürzer usw.), probieren Sie es einfach aus und Sie werden das Konzept leicht verstehen.
quelle
Heben ist ein Konzept, mit dem Sie eine Funktion in eine entsprechende Funktion innerhalb einer anderen (normalerweise allgemeineren) Einstellung umwandeln können
Schauen Sie sich http://haskell.org/haskellwiki/Lifting an
quelle
Nach diesem glänzenden tutorial , ist ein Funktors einige Container (wie
Maybe<a>
,List<a>
oderTree<a>
das kann Speicherelementen irgendeines anderen Typsa
). Ich habe die Java-Generika-Notation<a>
für den Elementtyp verwendeta
und stelle mir die Elemente als Beeren im Baum vorTree<a>
. Es gibt eine Funktionfmap
, die eine Elementkonvertierungsfunktion übernimmt,a->b
und einen Containerfunctor<a>
. Es gilta->b
für jedes Element des Containers, in das es effektiv umgewandelt wirdfunctor<b>
. Wenn nur das erste Argument angegeben wirda->b
,fmap
wartet auf dasfunctor<a>
. Das heißt,a->b
allein durch die Lieferung wird diese Funktion auf Elementebene in die Funktion umgewandeltfunctor<a> -> functor<b>
, die über Containern ausgeführt wird. Dies nennt man Hebender Funktion. Da der Container auch als Funktor bezeichnet wird , sind die Funktoren anstelle der Monaden eine Voraussetzung für das Heben. Monaden sind eine Art "parallel" zum Heben. Beide verlassen sich auf den Functor-Begriff und tun dies auchf<a> -> f<b>
. Der Unterschied besteht darin, dass das Hebena->b
für die Konvertierung verwendet wird, während Monad vom Benutzer definiert werden mussa -> f<b>
.quelle
r
bis zu einem Typ (verwenden wirc
für Abwechslung) sind Funktoren. Sie "enthalten" keinec
. In diesem Fall ist fmap eine Funktionszusammensetzung, die einea -> b
Funktion und einer -> a
Eins übernimmt , um Ihnen eine neuer -> b
Funktion zu geben . Immer noch keine Container. Wenn ich könnte, würde ich es auch für den letzten Satz noch einmal notieren.fmap
eine Funktion und "wartet" nicht auf irgendetwas; Der "Container", der ein Funktor ist, ist der springende Punkt beim Heben. Außerdem sind Monaden eher eine doppelte Idee zum Heben: Mit einer Monade können Sie etwas verwenden, das einige Male positiv angehoben wurde, als wäre es nur einmal angehoben worden - dies wird besser als Abflachen bezeichnet .To wait
,to expect
,to anticipate
sind Synonyme. Mit "Funktion wartet" meinte ich "Funktion antizipiert".b = 5 : a
undf 0 = 55
f n = g n
beide beinhalten eine Pseudomutation des "Containers". Auch die Tatsache, dass Listen normalerweise vollständig im Speicher gespeichert sind, während Funktionen normalerweise als Berechnung gespeichert werden. Aber Memoizing / Monorphic-Listen, die nicht zwischen Anrufen gespeichert werden, brechen beide den Mist aus dieser Idee heraus.