Nach Abschluss des ersten Problems (" Finden Sie das letzte Element einer Liste ") in der 99 Fragen Übungen , ich wollte sehen, wie meine Lösung im Vergleich zu anderen und ich fand diese Lösung .
%Vor% Diese Dokumentation scheint zu zeigen, dass foldr1
zwei Argumente benötigt, wobei das erste eine Funktion ist und der zweite ist eine Liste. Aber diese Definition scheint nur eine Funktion als Argument zu haben. Gibt es eine implizite Definition der Argumente, die so übergeben werden?
Ich habe die Definitionen von foldr1
, const
und id
nachgeschlagen, aber es fällt mir schwer zu verstehen, wie diese drei zusammenarbeiten, um das letzte Element in der Liste zurückzugeben.
Sie sind genau richtig. In Haskell kann eine Funktion, die zwei Argumente akzeptiert, tatsächlich als eine Funktion behandelt werden, die ein Argument verwendet und eine andere Funktion zurückgibt, die ein Argument verwendet. dies wird als currying bezeichnet. Beachten Sie, dass die Funktionssignatur für foldr1
lautet:
Während wir es oft als "eine Funktion betrachten, die eine Funktion und eine Liste als Argumente akzeptiert und einen Wert zurückgibt", ist es in Wirklichkeit eine Funktion, die eine Funktion als Argument akzeptiert und eine Funktion zurückgibt, die eine Liste übernimmt und zurückgibt ein Wert ".
Wie Mipadi erklärt, wird die Funktion curried. Das erklärt, wie das Listenargument dort ankommt, erklärt aber vielleicht nicht, wie die tatsächliche Faltung funktioniert.
Das const id
-Bit ist ein wenig trixy. foldr1
erwartet, etwas vom Typ a -> a -> a
zu erhalten. Die Definitionen dieser Funktionen sind
Also, alles zusammen vermasselnd, haben wir
%Vor% In der Reihenfolge der Wörter macht const id
dasselbe wie flip const
; Es ist eine 2-Argument-Funktion, die das erste Argument wegwirft und das zweite zurückgibt. Es ist nicht sehr offensichtlich, dass das so ist; IMHO, flip const
wäre klarer.
foldr1
ruft diese Funktion mit dem alten Wert als erstem Argument und dem nächsten Listenelement als zweitem Argument auf. Diese Funktion gibt immer das nächste Listenelement zurück. Die endgültige Ausgabe von foldr
ist die letzte Ausgabe der Funktion, die das letzte Element der gesamten Liste ist.
Ja, Ihre Intuition über Funktionen, die nicht alle Argumente benötigen, ist genau richtig. Und wenn eine Funktion eine andere Funktion als einen Parameter verwendet, um als Ergebnis eine andere Funktion zurückzugeben, wird sie "currying" genannt. Siehe: Ссылка .
(Als Randnotiz wurde dies tatsächlich von Haskell Curry entdeckt (oder wiederentdeckt), und so hat unser Haskell seinen Namen bekommen.)
Wenn die Idee des Currys noch Zeit braucht, um zu sinken, kann dies helfen:
Es gibt tatsächlich zwei Funktionen, die in Prelude
namens curry
und uncurry
definiert sind. Sie tragen die folgenden Typen:
uncurry
verwendet eine 2-Argument curried -Funktion (oder eine Funktion, die eine Funktion eines Arguments übernimmt, das eine Funktion eines Arguments zurückgibt) und erzeugt ein uncurrried Funktion oder eine Funktion, die alle Argumente alle auf einmal (als Tupel.)
curry
, wie Sie mit dem Namen und seinem Typ sagen können, geht in die andere Richtung, so dass es eine curried Funktion (eine Funktion, die alle Argumente auf einmal nimmt) und erzeugt eine Funktion, die ein Argument benötigt und eine Funktion zurückgibt, die das andere Argument übernimmt.
Die meisten Programmiersprachen arbeiten standardmäßig unbeirrt, Sie stellen alle Argumente zur Verfügung und erhalten ein Ergebnis, während Haskell standardmäßig voreingestellt ist.
Als Beispiel für uncurry
können wir eine einfache Funktion verwenden, (+)
:
Und wir könnten das auch mit const
machen, wenn wir wollen:
Aber eine uncurried-Version von const
ist einfach nicht sehr nützlich, weil es keinen Sinn hat, eine Funktion zu haben, die zwei Argumente akzeptiert und immer die erste zurückgibt, wenn Sie alle Argumente im voraus angeben müssen.
const
ist gerade deshalb nützlich, weil es curried ist und an einer Stelle angegeben werden kann, an der eine Funktion benötigt wird, die zwei Argumente benötigt und einfach die erste zurückgibt.
Wie in foldr1
, zum Beispiel:
Wo das erste Argument eine Curry-Funktion von zwei Argumenten ist.
Und da der Rückgabewert einer Funktion eine Funktion sein kann, kann dies auch mit const
sein:
const id
nimmt einfach ein Argument eines beliebigen Typs b
und gibt die Funktion id
zurück.
Also, wenn wir const id
Schritt für Schritt anwenden können:
const id 1
oder const id anyOtherValueHere
gibt nur die ID-Funktion zurück.
Welche kann so verwendet werden:
Also ignoriert const
wirklich das zweite Argument. Direkt darüber verhält sich id
wie 100.
Also nimmt foldr1 (const id)
einfach eine Liste und wendet id
auf jede Menge von zwei Elementen an und behält die zweite (weil const id
den Wert von id
für das zweite übergebene Argument zurückgibt) bis wir habe das letzte Element.
Sie haben Recht, dass Ihre beiden Beispiele durcheinander ersetzt werden können. Dies kann man sich wie in der Algebra-Klasse als algebraische Annullierung vorstellen.
%Vor% Ich kann die y
auf jeder Seite abbrechen:
Jetzt kann ich das x auf jeder Seite abbrechen:
%Vor%Schauen Sie sich die Wiki-Seite für foldr vs foldl und foldl an , um ein wenig mehr über foldr zu erfahren .
Um eine Vorstellung davon zu bekommen, wie myLast funktioniert, können wir etwas algebraische Suptation durchführen.
%Vor% Nun sollten wir die Definition von% co_de verwenden % insbesondere: foldr1
foldr1 f (x:xs) = f x (foldr1 f xs)
hat den Typ sig const id
, der mit b -> a -> a
identisch ist, und es stellt sich heraus, dass es genauso funktioniert, was eine Funktion ist, die das erste Argument ignoriert und das zweite Argument zurückgibt. Beispiel: flip const
* siehe unten für ein wenig mehr *
Dieser letzte Schritt ist möglicherweise nicht das, was Sie erwartet haben, aber wenn Sie die Definition von (const id) 1 3 == 3
überprüfen, enthält sie:
Welches Muster passt zusammen, wenn es nur ein Element in der Liste gibt, und gibt es zurück.
* Wie funktioniert foldr1
?
const id
gibt das erste Argument zurück und ignoriert es als zweites
Tags und Links haskell