jkeuhlen

Pattern Matching Trick

29 Jan 2019

About a month ago, I stumbled into on odd case of pattern matching. I had a set of data types like the following:

data Color = Red | Blue | Green | Black ...
data Car = Car { color :: Color,  ... }

I wanted to write a function that could take two cars and guarantee that they were the same color while doing other operations. A simple way to do this is to have an Eq instance for Color and then pull out the color from the car and check against it.

priceCompare :: Car -> Car -> Maybe ...
priceCompar car1 car2 = 
  if color car1 /= color car2 
    then Nothing 
    else ...

Now this technically works, but it doesn’t feel quite idiomatic. Typically in Haskell, when we want to have a guarantee about the structure of our data, we pattern match. Pattern matching can also be combined with guards to make a nice, and arguably more readable, function.

We’re also going to make one more efficiency update for this pattern. Eq instances could be slow depending on their implementation. Instead, we want to compare the data constructors like we do in a pattern match. There isn’t really a faster way to accomplish what we want. To do this, we’ll add a deriving Data to our definitions, and then be good to go. In order to compare the constructors, we’ll use a simple function utilizing Data.Data

constrEq :: (Data a) => a -> a -> Bool
constrEq x y = toConstr x == toConstr y

Then, we rewrite our function with our pattern matching + guards

priceCompare :: Car -> Car -> Maybe ...
priceCompare (Car color1 ...) (Car color2 ...) | color1 `constrEq` color2 = ...
priceCompare _ _ = Nothing 

Now we know that the cars in our first line of pattern matching always have the same color!