Is it possible to provide a custom pattern decomposition in Haskell?

800 views Asked by At

In Haskell, I have a module with a partial order type:

data PartialOrder a = PartialOrder [a] [(a, a)]

I don't export the value constructor because that's not how I want the type to be used, but I still want to be able to pattern match the PartialOrder type outside the module; is this possible? In particular, I want to be able to pattern match something that is not the type constructor, but instead, to pattern match something like the following:

f (PartialOrder xs le) = ...

Where le is a function implicitly defining the explicit ordering defined in the value constructor. I know such a facility is available in Scala, is there a way to do the same in Haskell?

Thanks in advance.

2

There are 2 answers

2
Tikhon Jelvis On BEST ANSWER

It sounds like a use case for ViewPatterns. You could write a type like:

data ViewPartialOrder a = ViewPartialOrder a (a -> a -> Ordering)

Write a function like:

viewOrder :: PartialOrder -> ViewPartialOrder
viewOrder (PartialOrder xs relation) = ...

then use the ViewPatterns extension to write code like this:

f (viewOrder -> ViewPartialOrder xs le) = ...

Of course, you should come up with better names for these things :P!

There's no way to have the same effect implicitly (ie without the viewOrder function), for better or worse. I think it's usually a good thing, making it clear that you're not matching the actual implementation of the type.

0
Tom Ellis On

The suggestion to use a view pattern is a fine one, but you can get much the same effect without a view pattern by precomposing with the "view" which is, after all, just a function.

So given

viewOfPartialOrder :: PartialOrder -> ViewPartialOrder
viewOfPartialOrder (PartialOrder xs relation) = ...

as suggested by Tikhon Jelvis (under a slightly different name), instead of

doSomethingWithAPartialOrder :: PartialOrder a -> Whatever
doSomethingWithAPartialOrder (viewOfPartialOrder -> ViewPartialOrder xs le) = ...

You can define

doSomethingWithAView :: ViewPartialOrder a -> Whatever
doSomethingWithAView (ViewPartialOrder xs le) = ...

doSomethingWithAPartialOrder :: PartialOrder a -> Whatever
doSomethingWithAPartialOrder = doSomethingWithAView . viewOfPartialOrder

Personally I find it easier to edit code presented in the latter way, but you should choose whatever you personally prefer.