Gibt es eine bequeme Möglichkeit, ein Muster als Prädikatfunktion zu verwenden?

10

Ich bin kürzlich auf Situationen gestoßen, in denen ich eine Prädikatfunktion an eine andere Funktion übergeben muss, und die gesuchte Logik lautet häufig: "Stimmt dieser Wert mit diesem Muster überein?"

Musterabgleich scheint in Deklarationen, doBlöcken und Listenverständnissen bevorzugt zu sein , aber es gibt eine Reihe von Funktionen, die ein Prädikat annehmen a -> Bool, bei denen es sehr praktisch wäre, ein Muster irgendwie zu übergeben. Zum Beispiel takeWhile, until, find, span, usw.

Bisher habe ich \a -> case a of MyCons _ -> True; otherwise -> Falseeine benannte Funktion a la gemacht oder geschrieben, let myPred (MyCons _) = True; myPred _ = False inaber beide scheinen schrecklich hässlich und nicht sehr idiomatisch zu sein. Der "offensichtliche" (und falsche) Weg wäre so etwas wie, \(MyCons _) -> Trueaber das wirft natürlich den Fehler auf, parteiisch zu sein, und selbst dann scheint es einen saubereren Weg zu geben.

Gibt es eine prägnantere / sauberere Möglichkeit, so etwas zu tun? Oder gehe ich die Dinge völlig falsch an?

David Sampson
quelle
1
Vielleicht ist dies eine Sache mit "persönlichem Geschmack", aber wenn Sie dieses Prädikat nur an einer Stelle benötigen, wäre ich mit der letKlausel, die Sie nicht mögen , sehr zufrieden - obwohl ich die entsprechende whereKlausel bevorzuge , damit die Hauptdefinition nicht durcheinander gerät. Wenn Sie dieses Dienstprogramm mehr als einmal benötigen, definieren Sie es natürlich als Funktion der obersten Ebene.
Robin Zigmond
Es funktioniert auf jeden Fall gut. Meine Frage war etwas motiviert, wie beeindruckend prägnant Haskell normalerweise ist. Es fühlt sich normalerweise so an, als hätte Haskell nur sehr wenig Ideenüberschneidungen und hält die Flusen auf ein Minimum. Es ist also nicht unbedingt notwendig, dass ich den let myPred...Stil für schlecht halte , aber er fühlt sich viel ausführlicher an, als ich es für eine sehr einfache Idee erwarten würde, was mich zu der Frage führt, ob ich den falschen Baum belle.
David Sampson
2
Sie können sich Prismen (von der Linse) ansehen. Sie sind wie erstklassige zusammensetzbare Muster
luqui
1
Ich denke, wir müssten ein Beispiel dafür sehen, wo Sie diese Art von Funktion höherer Ordnung verwenden. Ein Teil von mir möchte sagen, dass das Problem in dem Design liegt, das in erster Linie ein solches Prädikat erfordert.
Chepper
Die Haskell98-Methode besteht darin, die Case-Matching-Funktion (Dekonstruktionsfunktion) für Ihren Datentyp wie maybe :: b -> (a -> b) -> Maybe a -> bund zu definieren und sie bool :: a -> a -> Bool -> adann mit Booleschen produzierenden Funktionen als Argument (e) zu verwenden. zB myCons z f (MyCons x) = f x ; myCons z f _ = zdann anrufen myCons False (const True) aMyConsValue. Dies ist fast das, was Sie geschrieben haben. Es ist nur eine weitere Ebene der "Indirektion" / "Abstraktion" über funktionale Argumente eingebaut.
Will Ness

Antworten:

7

Sie können die Spracherweiterung LambdaCase verwenden \case MyCons _ -> True; _ -> False, obwohl dadurch nicht so viele Zeichen gespeichert werden .

Ich glaube , dass Sie eine Reihe von Funktionen schreiben könnten constructedWith :: (Generic a) => (b -> a) -> a -> Bool, constructedWith2 :: (Generic a) => (b -> c -> a) -> a -> Boolaber ich bin nicht kompetent genug , um mit Generics es zu implementieren , ohne ein paar Stunden Dinge testen. Ich werde es versuchen und meine Antwort bearbeiten, wenn ich es herausfinden kann oder wenn es eine Sackgasse ist.

EDIT: Ja, du kannst es schaffen! Hier ist ein Link zu meinem Code, der alles von Grund auf neu implementiert:

https://repl.it/@lalaithion/ConstructedWith

Die Verwendung von http://hackage.haskell.org/package/generic-deriving-1.13.1/docs/Generics-Deriving-ConNames.html für alle allgemeinen Code-Installationen ist jedoch möglicherweise besser.

Izaak Weiss
quelle