Search code examples
haskellderivingderivingvia

Is it possible to provide default instances of some type class X for my type class Y?


To elaborate, it is often possible to provide default implementations for type class instance functions, but I wonder if it is also possible to provide default implementations for type class instances of other type classes.

For instance, say I'm implementing type class Y and I want all instances a of Y to satisfy X a for some other type class X. Initially I was trying to do this by writing instance Y a => X a where ..., but saw this was not really possible (Haskell Constraint is no smaller than the instance head). However, unlike in the more general case described in the other question where there might be more than one type class constraint, I've just got one class constraint in my case, so I figure there might be a way to do this at the class definition level, maybe using a Haskell language extension.

The method described in the other question doesn't seem to work too smoothly - let's say X is actually Ord. Wrapping Ord by some newtype prevents direct usage of Ord functions on the original type.


Solution

  • The usual trick here is to define a newtype wrapper with the instance you want. See WrappedMonoid for an example of this. In your case:

    newtype WrappedY a = WrapY { unwrapY :: a }
    
    instance Y a => X (WrappedY a) where 
      -- your default implementation here
    

    Then, a type that has an instance of Y can derive its instance of X using the new DerivingVia extension.

    {-# LANGUAGE DerivingVia #-}
    
    data SomeType = ...
      deriving X via WrappedY SomeType
    
    instance Y SomeType where
      -- your implementation here