Beträgt harkells Foldr immer ein Zwei-Parameter-Lambda?

7

Haskell newb hier

Ich arbeite an diesem Problem in Haskell:

%Vor%

Die Lösung (die ich nachschlagen musste) verwendet foldr:

%Vor%

Dieser foldr, entsprechend der Lösung, nimmt zwei Parameter, x und acc. Es sieht so aus, als ob alle Folder diese Parameter haben; Gibt es da eine Ausnahme? Wie ein Folder, der 3 oder mehr braucht? Wenn nicht, ist diese Konvention redundant und kann die Formel mit weniger Code geschrieben werden?

    
Mark Karavan 12.01.2015, 16:36
quelle

3 Antworten

14

foldr nimmt eine Funktion von 2 Argumenten, dies hindert jedoch nicht daran, eine Funktion von 3 Argumenten zu nehmen, vorausgesetzt, dass die Funktion die richtige Typ-Signatur hat.

Wenn wir eine Funktion hätten

%Vor%

Mit

%Vor%

Wo wir g an foldr weitergeben wollen, dann (a -> b -> b) ~ (x -> y -> z -> w) (wobei ~ Gleichheit des Typs ist). Da -> rechts assoziativ ist, können wir die Signatur g als

schreiben %Vor%

und seine Bedeutung ist dieselbe. Jetzt haben wir eine Funktion von zwei Parametern erzeugt, die eine Funktion eines Parameters zurückgibt. Um dies mit dem Typ a -> b -> b zu vereinheitlichen, müssen wir nur die Argumente anordnen:

%Vor%

Das bedeutet, dass b ~ z -> w , also y ~ b ~ z -> w und a ~ x so g 's Typ wirklich

sein muss %Vor%

impliziert

%Vor%

Dies ist sicherlich nicht unmöglich, obwohl eher unwahrscheinlich. Unser Akkumulator ist stattdessen eine Funktion, und das ist für mich mit DiffLists zu demonstrieren:

%Vor%

Beachten Sie, dass foldr append (const []) xs eine Funktion zurückgibt, die wir auf [] anwenden, um eine Liste umzukehren. In diesem Fall haben wir einen Alias ​​für Funktionen vom Typ [a] -> [a] namens DiffList vergeben, aber das ist wirklich nicht anders als das Schreiben von

%Vor%

was eine Funktion von 3 Argumenten ist.

    
bheklilr 12.01.2015, 16:53
quelle
4

Wie bei allen Dingen in Haskell sehen Sie sich die Typen der Dinge an, die Sie als Wegweiser für jede Funktion in ghci verwenden können.

Betrachten wir dies für foldr sehen wir:

%Vor%

Diese leicht abstrakte Zeichenkette kann in Englisch geschrieben werden als:

foldr ist eine Funktion, die

benötigt

1) eine Funktion mit zwei Parametern vom Typ a und einem vom Typ b und gibt etwas vom Typ b

zurück

2) Ein Wert vom Typ b

3) Eine Liste von Werten vom Typ a

Und gibt einen Wert vom Typ b

zurück

Wobei a und b Typvariablen sind (siehe hier für ein gutes Tutorial zu ihnen), das kann mit einem beliebigen Typ ausgefüllt werden.

    
Simon Gibbons 12.01.2015 16:46
quelle
3

Es stellt sich heraus, dass Sie Ihr compress Problem mit einem foldr mit einer Drei-Argument-Funktion lösen können.

%Vor%

Lass uns das analysieren. Erstens können wir die Lesbarkeit verbessern, indem wir die letzten beiden Zeilen in

ändern %Vor%

Dies macht deutlich, dass eine ternäre Funktion nichts anderes als eine binäre Funktion ist, die eine unäre Funktion zurückgibt. Der Vorteil, es auf diese Weise zu betrachten, ist, dass foldr am besten verstanden wird, wenn eine binäre Funktion übergeben wird. In der Tat übergeben wir eine binäre Funktion, die zufällig eine Funktion zurückgibt.

Konzentrieren wir uns jetzt auf Typen:

%Vor%

Also, x::a ist das Element der Liste, auf die wir folden. Die Funktion k ist das Ergebnis der Faltung auf dem Listenende. Das Ergebnis von f x k hat etwas vom selben Typ wie k .

%Vor%

Die allgemeine Idee hinter dieser anonymen Funktion ist wie folgt. Der Parameter k spielt die gleiche Rolle wie acc im OP-Code, außer dass es eine Funktion ist, die das vorherige Element w in der Liste erwartet, bevor die akkumulierte komprimierte Liste erstellt wird.

Konkret verwenden wir jetzt k x , wenn wir acc verwenden, und leiten das aktuelle Element an den nächsten Schritt weiter, da zu diesem Zeitpunkt x zum vorherigen Element w wird. Auf der obersten Ebene übergeben wir z an die Funktion, die von foldr f (const []) zurückgegeben wird.

Diese compress -Variante ist im Gegensatz zur veröffentlichten Lösung faul. In der Tat muss die veröffentlichte Lösung die gesamte Liste scannen, bevor sie etwas produziert: Dies liegt an ( \x acc -> ...) ist streng in acc und an der Verwendung von last xs . Stattdessen gibt die obige Komprimierung Listenelemente in aus eine "streaming" Mode. Tatsächlich funktioniert es auch mit unendlichen Listen:

%Vor%

Davon abgesehen denke ich, dass die Verwendung eines foldr hier ein bisschen komisch wirkt: Der obige Code ist wohl weniger lesbar als die explizite Rekursion.

    
chi 12.01.2015 18:24
quelle

Tags und Links