Verbessere meine Haskell-Implementierung von Filter

8

Ich habe mir kürzlich selbst Haskell beigebracht, und eine meiner Übungen bestand darin, die Funktion filter erneut zu implementieren. Von all den Übungen, die ich durchgeführt habe, scheint mir meine Antwort am hässlichsten und längsten zu sein. Wie könnte ich es verbessern? Gibt es Haskell-Tricks, die ich noch nicht kenne?

%Vor%

Danke

    
Mantas Vidutis 10.06.2010, 02:42
quelle

5 Antworten

15

Der einfachste Weg, Ihre Implementierung zu verbessern, ist Wächter . Anstelle von pattern = value können Sie schreiben schreiben pattern | boolean = value ; Dies trifft nur zu, wenn boolean wahr ist. So können wir

bekommen %Vor%

( otherwise ist nur ein Synonym für True .) Jetzt haben wir filter p xs an zwei Stellen, sodass wir sie in eine where -Klausel verschieben können; Diese werden von allen geteilt, die ein gemeinsames Muster haben, auch wenn es einen anderen Schutz hat:

%Vor%

(Diese Implementierung ist die eine verwendet von GHCs Prelude .)

Nun sind keine davon rekursiv. Dies kann nachteilig sein, aber es macht die Funktion faul. Wenn wir eine tail-rekursive Version wollen, könnten wir

schreiben %Vor%

Beachten Sie jedoch, dass dies auf unendlichen Listen fehlschlagen würde (obwohl alle anderen Implementierungen funktionieren), dank der reverse , also machen wir es mit $! strikt. (Ich denke, ich habe das richtig gemacht - ich hätte die falsche Variable erzwingen können. Ich denke, ich habe diese richtig verstanden.)

Diese Implementierungen sehen alle wie Ihre aus. Es gibt natürlich andere. Einer basiert auf foldr :

%Vor%

Wir nutzen den Punkt-freien Stil hier; Da xs das letzte Argument sowohl für filter4 als auch für foldr check [] ist, können wir es genauso vermeiden wie beim letzten Argument von check .

Sie könnten auch die Listenmonade nutzen:

%Vor%

Die Listenmonade repräsentiert Nichtdeterminismus. Sie wählen ein Element x von xs , stellen sicher, dass es p erfüllt, und geben es dann zurück, wenn dies der Fall ist. Alle diese Ergebnisse werden dann gesammelt. Aber beachte, dass dies jetzt allgemeiner ist; das funktioniert für jede MonadPlus (eine Monade, die auch ein Monoid ist, das heißt, eine assoziative binäre Operation mplus - ++ für Listen - und ein Identitätselement mzero - [] für Listen), wie [] oder Maybe . Zum Beispiel filter5 even $ Just 1 == Nothing und filter5 even $ Just 2 == Just 2 .

Wir können auch die foldr -basierte Version anpassen, um eine andere generische Typ-Signatur zu erhalten:

%Vor%

Das Data.Foldable-Modul bietet die Klasse Foldable type, die eine beliebige Struktur darstellt, die wie eine Liste fold ed sein kann (statt das Ergebnis in eine generische Monoid zu legen). Unsere filter erfordert eine MonadPlus Einschränkung für das Ergebnis damit wir return x schreiben können. Die Funktion foldMap benötigt eine Funktion, die alles in Elemente eines Monoid konvertiert und dann alle zusammen verkettet. Der Unterschied zwischen dem f a auf der linken Seite und dem m a auf der rechten Seite bedeutet, dass Sie beispielsweise filter6 a Maybe erhalten und eine Liste zurück erhalten könnten.

Ich bin mir sicher, dass es (viele!) andere Implementierungen von filter gibt, aber das sind die 6, an die ich relativ schnell denken könnte. Nun, welche mag ich eigentlich am liebsten? Es ist ein Tossup zwischen dem direkten filter2 und dem foldr -basierten filter4 . Und filter5 ist nett für seine generische Typ-Signatur. (Ich glaube nicht, dass ich jemals eine Typensignatur wie filter6 benötigt habe.) Die Tatsache, dass filter2 von GHC verwendet wird, ist ein Plus, aber GHC verwendet auch einige funky rewrite-Regeln, also ist es nicht offensichtlich mir, dass es ohne diese überlegen ist. Persönlich würde ich wahrscheinlich mit filter4 (oder filter5 , wenn ich die genericity benötigte), aber filter2 ist definitiv in Ordnung.

    
Antal Spector-Zabusky 10.06.2010, 03:43
quelle
7

Wie wäre es mit einem Listenverständnis?

%Vor%     
user340127 10.06.2010 21:18
quelle
3

Du könntest es zumindest etwas DRYEN, indem du den üblichen myfilter f xs code herausholst:

%Vor%     
Mark Rushakoff 10.06.2010 02:47
quelle
2

Zum Vergleich, hier ist die Implementierung von Wikipedia:

%Vor%     
Gabe 10.06.2010 02:54
quelle
1

In Haskell können (und sollten) Sie Wachen anstelle von if- then-else:

%Vor%

Dies ist im Grunde die gleiche Definition wie verwendet in der Standardbibliothek .

    
sth 10.06.2010 02:49
quelle

Tags und Links