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, do
Blö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 -> False
eine benannte Funktion a la gemacht oder geschrieben, let myPred (MyCons _) = True; myPred _ = False in
aber beide scheinen schrecklich hässlich und nicht sehr idiomatisch zu sein. Der "offensichtliche" (und falsche) Weg wäre so etwas wie, \(MyCons _) -> True
aber 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?
let
Klausel, die Sie nicht mögen , sehr zufrieden - obwohl ich die entsprechendewhere
Klausel 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.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.maybe :: b -> (a -> b) -> Maybe a -> b
und zu definieren und siebool :: a -> a -> Bool -> a
dann mit Booleschen produzierenden Funktionen als Argument (e) zu verwenden. zBmyCons z f (MyCons x) = f x ; myCons z f _ = z
dann anrufenmyCons 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.Antworten:
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 -> Bool
aber 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.
quelle