Czy istnieje wygodny sposób użycia wzorca jako funkcji predykatu?

10

Niedawno wpadłem na sytuacje, w których muszę przekazać funkcję predykatu do innej funkcji, i dość często logika, której szukam, to w zasadzie „czy ta wartość pasuje do tego wzorca?”

Dopasowywanie wzorców wydaje się być preferowane w deklaracjach, doblokach i opisach list, ale istnieje wiele funkcji, które przyjmują predykaty a -> Bool, w których bardzo przydatne byłoby jakoś przekazać wzorzec. Na przykład takeWhile, until, find, span, itd.

Do tej pory robiłem \a -> case a of MyCons _ -> True; otherwise -> Falselub pisałem nazwaną funkcję a la, let myPred (MyCons _) = True; myPred _ = False inale oba wydają się strasznie brzydkie i niezbyt idiomatyczne. „Oczywisty” (i zły) sposób byłby czymś podobnym, \(MyCons _) -> Trueale generuje to błąd, ponieważ jest stronniczy, oczywiście, i nawet wtedy wydaje się, że musi istnieć czystszy sposób.

Czy istnieje bardziej zwięzły / czysty sposób na zrobienie czegoś takiego? Czy też chodzi o rzeczy całkowicie niewłaściwe?

David Sampson
źródło
1
Być może jest to kwestia „osobistego gustu”, ale jeśli potrzebujesz tego predykatu tylko w jednym miejscu, byłbym całkiem zadowolony z letklauzuli, której nie lubisz - chociaż wolę whereklauzulę równoważną , więc nie zaśmieca to głównej definicji. Oczywiście, jeśli będziesz potrzebować tego narzędzia więcej niż jeden raz, zdefiniuj je jako funkcję najwyższego poziomu.
Robin Zigmond,
Z pewnością działa dobrze. Moje pytanie było nieco motywowane tym, jak imponująco zwięzły jest zazwyczaj Haskell. Zwykle wydaje się, że idiomatyczny Haskell ma bardzo mało powielania pomysłów i ogranicza puch do minimum. Więc niekoniecznie uważam, że let myPred...styl jest zły , ale wydaje się bardziej gadatliwy, niż oczekiwałbym bardzo prostego pomysłu, co prowadzi mnie do zastanowienia się, czy nie szczekam na niewłaściwym drzewie.
David Sampson
2
Możesz spojrzeć na pryzmaty (z obiektywu). Są jak pierwszorzędne wzorce do komponowania
luqui
1
Myślę, że powinniśmy zobaczyć przykład zastosowania tego typu funkcji wyższego rzędu. Część mnie chce powiedzieć, że problem dotyczy projektu, który wymaga takiego predykatu w pierwszej kolejności.
chepner
droga Haskell98, za to jest określenie orzecznictwa, dobieraniu (dekonstrukcji) funkcji dla danego typu danych, jak maybe :: b -> (a -> b) -> Maybe a -> bi bool :: a -> a -> Bool -> a, a następnie używać go z funkcji (y) jako argument (y) Boolean produkujących. np. myCons z f (MyCons x) = f x ; myCons z f _ = znastępnie zadzwoń myCons False (const True) aMyConsValue. jest to prawie to, co napisałeś, ma tylko jeden poziom „pośredni” / „abstrakcyjny” za pomocą funkcjonalnych argumentów, wrzucony w to.
Czy Ness

Odpowiedzi:

7

Możesz użyć rozszerzenia językowego LambdaCase \case MyCons _ -> True; _ -> False, ale nie oszczędza to tylu znaków.

Wierzę, że możesz napisać serię funkcji constructedWith :: (Generic a) => (b -> a) -> a -> Bool, constructedWith2 :: (Generic a) => (b -> c -> a) -> a -> Boolale nie jestem wystarczająco kompetentny w Generics, aby wdrożyć go bez kilku godzin testowania. Spróbuję tego i zredaguję swoją odpowiedź, jeśli uda mi się to rozgryźć lub jeśli to ślepy zaułek.

EDYCJA: Tak, możesz to zrobić! Oto link do mojego kodu, który implementuje to wszystko od zera:

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

Jednak użycie czegoś takiego jak http://hackage.haskell.org/package/generic-deriving-1.13.1/docs/Generics-Deriving-ConNames.html dla wszystkich ogólnych kodów instalacyjnych może być lepsze.

Izaak Weiss
źródło