'filterM' für Container wie 'Data.Map.Map' oder 'Data.Set.Set'

9

Kurz gesagt: Wie würden Sie Elemente eines Map oder Set auf einer Monade filtern? Prädikat in Haskell?

Ich könnte mir zwei Möglichkeiten vorstellen:

a) Round-Trip durch eine Liste und filterM (wahrscheinlich nicht sehr effizient):

%Vor%

b) Wenn das Prädikat nicht von Natur aus monadisch ist, sondern z.B. ist ein Vergleich zu den    Zustand in State monad; dann können wir Data.Map.filter verwenden (ziemlich speziell    Fall):

%Vor%

Gibt es einen besseren Weg, dies zu tun?

Hier ist ein kleines Beispielprogramm zur Demonstration.

%Vor%

Update : Ich habe einen Benchmark zwischen verschiedenen Implementierungen von filterMapM erstellt. Es stellt sich heraus, dass die Rundreise durch eine Liste eigentlich ziemlich gut ist. Überraschenderweise war es sogar noch besser als ein Umsetzungsrecht auf die interne Struktur von Map . Der Code und die Daten sind hier verfügbar.

    
Lemming 13.11.2014, 11:05
quelle

2 Antworten

3

Die beiden Ansätze haben unterschiedliche Semantiken und Implikationen für die Effizienz.

Wenn Sie eine Liste durchlaufen, können Sie die Filterung durch alle vorherigen Vergleiche beeinflussen, so dass das Endergebnis von der Reihenfolge beeinflusst werden kann, in der die Elemente besucht werden. Im zweiten Fall ist die Filterung jedoch eine reine Funktion, so dass die Antwort dieselbe ist, egal in welcher Reihenfolge die Vergleiche gemacht werden.

Zum Beispiel könnte der Benutzer, der die Fragen beantwortet, die Anzahl der geraden und ungeraden Zahlen ungefähr gleich halten, und somit hängt die Frage, ob der Benutzer eine bestimmte Zahl mag, von allen Zahlen ab, die zuvor präsentiert wurden. p>

Auf der anderen Seite ist hier der Code für M.filter :

%Vor%

Wichtig ist, dass die Form des Codes - die resultierende Baumstruktur - stark von der Struktur des ursprünglichen Baumes beeinflusst wird. Vielleicht wird nur ein kleiner Ausgleich benötigt. Dies könnte viel effizienter sein, als den Baum aus Null Wissen mit M.fromList wiederherzustellen.

Das Ergebnis ist, dass Sie sich in dem Fall filterM1 Gedanken über die Reihenfolge machen sollten, in der die Vergleiche gemacht werden. Vielleicht gibt M.toList eine akzeptable Reihenfolge, oder vielleicht möchten Sie reverse . M.toList , oder ...

Im zweiten Fall müssen Sie sich nicht darum kümmern, also können Sie M.filter die gesamte Arbeit erledigen lassen und die Kenntnisse über die Datenstruktur nutzen.

Update: Ich habe gerade die Funktionen M.toAscList und M.fromAscList bemerkt, also ist diese Version von filterMapM1 vielleicht etwas effizienter:

%Vor%     
ErikR 13.11.2014, 18:26
quelle
1

Momentan glaube ich nicht, dass es eine allgemeinere Abstraktion gibt, die filterM direkt unterstützt. Traversable nicht, weil traverse die Form der Struktur nicht ändern kann. Ich denke, dass es technisch möglich ist, dies mit Objektiv zu tun, aber die Dokumentation schlägt vor, dass Sie das wirklich nicht tun sollten und ich denke, dass es sowieso durch eine andere Struktur rockt.

Sie könnten so etwas verwenden (nicht kompilierbar, weil filter kein Klassenmitglied ist):

%Vor%

Ob dies mehr oder weniger effizient ist als das Runden durch eine Liste, hängt wahrscheinlich von der Struktur ab. Es ist wohl weniger sauber.

    
John L 14.11.2014 00:25
quelle

Tags und Links