Say I have a data type like so:
data NumCol = Empty | Single Int | Pair Int Int | Lots [Int]
Now I wish to filter out the elements matching a given constructor from a [NumCol]
. I can write it for, say, Pair
:
get_pairs :: [NumCol] -> [NumCol] get_pairs = filter is_pair where is_pair (Pair _ _) = True is_pair _ = False
This works, but it's not generic. I have to write a separate function for is_single
, is_lots
, etc.
I wish instead I could write:
get_pairs = filter (== Pair)
But this only works for type constructors that take no arguments (i.e. Empty
).
So the question is, how can I write a function that takes a value and a constructor, and returns whether the value matches the constructor?
At least get_pairs
itself can be defined relatively simply by using a list comprehension to filter instead:
get_pairs xs = [x | x@Pair {} <- xs]
For a more general solution of matching constructors, you can use prisms from the lens
package:
{-# LANGUAGE TemplateHaskell #-} import Control.Lens import Control.Lens.Extras (is) data NumCol = Empty | Single Int | Pair Int Int | Lots [Int] -- Uses Template Haskell to create the Prisms _Empty, _Single, _Pair and _Lots -- corresponding to your constructors makePrisms ''NumCol get_pairs :: [NumCol] -> [NumCol] get_pairs = filter (is _Pair)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With