Is it possible to use a GHC extension to define a new type class that generalizes to tuples of arbitrary length?
There have been a few questions already about the behavior of builtin classes in Prelude and Base (some classes support up to 15-element tuples, some up to 7) and about the (non-)possibility of extending these classes.
Prelude and Base behavior: Haskell Tuple Size Limit
extending Show with new definitions: Extend a Show instance to a Tuple of any size
I'm asking a slightly different question. If I'm making an entirely new type class, is it possible to add an instance rule that handles tuples of arbitrary length (possibly using a GHC extension)?
Here's an example of such a class called PartialOrder. I want to allow tuples of arbitrary size to be partially compared using the following rule
(a,b ... , z) <= (a1,b1, ... , z1) iff (a <= a1) && (b <= b1) && ... && (z <= z1)
Here's my first stab at a definition using the traditional "define the class for tuples up to some arbitrary size" approach.
Is there a GHC extension that can be used to write instance definitions that cover tuples of arbitrary length?
I think I can use Template Haskell or an external program to generate definitions in advance, but not generate them on demand like C++ templates.
-- Sets equipped with the (is_subset) operation are an example of a
-- partial order.
--
-- {} < {a} less than
-- {} = {} equal to
-- {a, b} > {b} greater than
-- {a} ~ {b} incomparable
--
-- in order to define a partial order we need a definition of (<=)
data PartialOrdering = POLessThan | POGreaterThan | POEqual | POIncomparable deriving (Eq, Show)
class PartialOrder a where
lessThanEq :: a -> a -> Bool
instance PartialOrder PartialOrdering where
lessThanEq POIncomparable _ = False
lessThanEq _ POIncomparable = False
-- with incomparables dealt with...
lessThanEq POLessThan _ = True
lessThanEq POEqual POLessThan = False
lessThanEq POEqual _ = True
lessThanEq POGreaterThan POGreaterThan = True
lessThanEq POGreaterThan _ = False
-- note this is different from the semantics for Ord applied to tuples,
-- which uses lexicographic ordering.
--
-- (a,b) is less than or equal to (c,d) iff
-- a <= b and c <= d
-- 2 element tuple
instance (PartialOrder a, PartialOrder b) => PartialOrder (a, b) where
lessThanEq (a,b) (c,d) = (lessThanEq a c) && (lessThanEq b d)
-- 3 element tuple
instance (PartialOrder a, PartialOrder b, PartialOrder c) => PartialOrder (a, b, c) where
lessThanEq (a,b,c) (d,e,f) = (lessThanEq a d) && (lessThanEq b e) && (lessThanEq c f)
-- 4 element tuple
instance (PartialOrder a, PartialOrder b, PartialOrder c, PartialOrder d) => PartialOrder (a, b, c, d) where
lessThanEq (a,b,c,d) (e,f,g,h) = (lessThanEq a e) && (lessThanEq b f) && (lessThanEq c g) && (lessThanEq d h)
-- etc.
main = putStrLn "hi"