David Sampson
David Sampson

Reputation: 747

Is there a convenient way to use a pattern as a predicate function?

I've recently been running into situations where I need to pass a predicate function into another function, and quite often the logic I am looking for is essentially "does this value match this pattern?"

Pattern matching seems to be preferred in declarations, do blocks, and list comprehensions, but there are a number of functions that take a predicate a -> Bool, where it would be very handy to somehow pass in a pattern. For example, takeWhile, until, find, span, etc.

Thus far I've been doing \a -> case a of MyCons _ -> True; otherwise -> False, or writing a named function a la let myPred (MyCons _) = True; myPred _ = False in but they both seem terribly ugly and not very idiomatic. The "obvious" (and wrong) way would be something like \(MyCons _) -> True but that throws an error for being partial, naturally, and even then it feels like there must be a cleaner way.

Is there a more succinct / clean way to do this sort of thing? Or am I going about things entirely the wrong way?

Upvotes: 10

Views: 467

Answers (1)

Izaak Weiss
Izaak Weiss

Reputation: 1310

You can use the Language Extension LambdaCase to use \case MyCons _ -> True; _ -> False, although this doesn't save that many characters.

I believe you could write a series of functions constructedWith :: (Generic a) => (b -> a) -> a -> Bool, constructedWith2 :: (Generic a) => (b -> c -> a) -> a -> Bool, but I'm not competent enough with Generics to implement it without a few hours testing things out. I will try this, and edit my answer if I can figure it out, or if it is a dead end.

EDIT: Yes, you can do it! Here's a link to my code, which implements it all from scratch:

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

However, using something like http://hackage.haskell.org/package/generic-deriving-1.13.1/docs/Generics-Deriving-ConNames.html for all of the generic code plumbing might be better.

Upvotes: 7

Related Questions