Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test if a value matches a constructor

Tags:

haskell

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?

like image 309
ridiculous_fish Avatar asked Aug 30 '14 23:08

ridiculous_fish


1 Answers

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) 
like image 106
Ørjan Johansen Avatar answered Oct 25 '22 01:10

Ørjan Johansen