I've came to an interesting situation when I tried to decompose one typeclass I needed for restoring tree from a list representation. The idea was to represent property of elements to be relative each to other in original hierarchy.
Consider next traits of data types
class HierarchyOrd a where
-- | Compares two objects for being on the same branch of hierarchy
-- LT/GT lower/higher in hierarchy, EQ on the same node
hierarchyCompare :: a -> a -> Maybe Ordering
class HierarchyOrd a => Hierarchy a where
-- | Get information for common joint of branches for two objects
-- Either one of them already on joint node (parent)
-- or we need another object that represent that joint
hierarchyJoint :: a -> a -> Either Ordering a
-- hierarchyCompare x y = either Just (const Nothing) (hierarchyJoint x y)
-- Sample for FilePath
instance Hierarchy FilePath where
hierarchyJoint x y = case (length x', length y', length z') of
(a, b, c) | a == c && b == c -> Left EQ
(a, _, c) | a == c -> Left GT
(_, b, c) | b == c -> Left LT
_ -> Right (joinPath z')
where
[x', y'] = map splitDirectories [x, y]
skel = takeWhile id (zipWith (==) x' y')
z' = zipWith const x' skel -- common prefix
instance HierarchyOrd FilePath where
hierarchyCompare x y = either Just (const Nothing) (hierarchyJoint x y)
As you can see HierarchyOrdering
is a subset of Hierarchy
for which we only need to implement ordering without requiring of building new node. In this particular case (FilePath
) having two non-overlapping functionality isn't feasible and even may result in extra-work (splitting directories twice for hierarchyCompare
and hierarchyJoint
). That's why it was decided to cover functionality of hierarchyCompare
by hierarchyJoint
since it makes no sense to call it if we got Just _
.
Question is: how to be with default implementation of hierarchyCompare
when object is defined on Hierarchy
. Maybe there is some extension that allows to expose such kind of relation between typeclasses in a more descriptive way (wich allows default implementation)?
I think you're looking for the GHC DefaultSignatures
extension? That let's you do:
class HierarchyOrd a where
-- | Compares two objects for being on the same branch of hierarchy
-- LT/GT lower/higher in hierarchy, EQ on the same node
hierarchyCompare :: a -> a -> Maybe Ordering
default hierarchyCompare :: Hierarchy a=> a -> a -> Maybe Ordering
hierarchyCompare x y = either Just (const Nothing) (hierarchyJoint x y)
and then you can simply provide an empty instance declaration:
instance HierarchyOrd FilePath