You could do it like this:
{-# LANGUAGE ConstraintKinds, TypeFamilies, FlexibleInstances #-}
import qualified Data.Set as Set
import Data.Set (Set)
import qualified Data.List as List
import Data.Kind
class Mappable m where
type C m a :: Constraint
type C m a = () -- no constraint by default
mmap :: (C m a, C m b) => (a -> b) -> m a -> m b
instance Mappable Set where
type C Set a = Ord a -- overwrite default with the Ord constraint
mmap = Set.map
instance Mappable [] where
mmap = List.map
@rae also did a talk about partial type constructors which is another stab at this problem using constraints (solving the constrained functor problem is actually more of a useful side effect of solving a more general problem in that talk).
I can’t tell you anything about the usability of either approach, I don’t have experience with them.