There's a fine tradition of including 'smart constructor' methods in an interface (class):
class Collection c a where
empty :: c a
singleton :: a -> c a
-- etc
It would be nice to supply them as pattern-synonyms:
{-# LANGUAGE PatternSynonyms #-}
instance Ord a => Collection [] a where
empty = []
singleton x = [x]
pattern PEmpty = []
pattern PSingleton x = [x]
But you can't put PatSyns inside classes. I've got something working, but it seems an awful lot of ugly code. Can anyone suggest ways to clean it up? (Specific uglinesses itemised below.)
{-# LANGUAGE ViewPatterns #-}
pattern PEmpty :: (Eq (c a), Collection c a) => c a
pattern PEmpty <- ((==) empty -> True) where
PEmpty = empty
pattern PSingleton :: (Ord a, Collection c a) => a -> c a
pattern PSingleton x <- (isSingleton -> Just x) where
PSingleton x = singleton x
-- needs an extra method in the class:
isSingleton :: c a -> Maybe a
-- instance ...
isSingleton [x] = Just x
isSingleton _ = Nothing
- It's annoying that these need to be explicitly bi-directional patterns; especially since the 'under
where' line is so directly comparable to the instance overload. - For the
emptypattern I have to introduce an explicit(==)test and supportingEqconstraint -- to achieve a simple pattern match. (I suppose I could call anisEmptymethod.) - For the
singletonpattern, I've avoided an explicit(==)test, but needed to double-up on a method in the class. - I really do not like
ViewPatterns; I'd hope PatSyns could provide some way to avoid them.