Есть два способа - классический через
FunctionalDependencies и неоклассический - через
TypeFamilies.
Функциональные зависимости сделаны специально для классов с несколькими параметрами:
{-# LANGUAGE FunctionalDependencies #-}
class Collects e ce | ce -> e where
empty :: ce
insert :: e -> ce -> ce
member :: e -> ce -> Bool
toList :: ce -> [e]
usage :: Collects e ce => ce -> Maybe e
Семейства типов более общие и могут работать отдельно от классов. Но внутри классов можно определять так называемые "ассоциированные типы". Тогда у класса не будет этого параметра, но экземпляр должен будет предоставить функцию из себя в ассоциированный тип:
{-# LANGUAGE TypeFamilies #-}
class Collects ce where
type Elem ce
empty :: ce
insert :: Elem ce -> ce -> ce
member :: Elem ce -> ce -> Bool
toList :: ce -> [Elem ce]
usage :: Collects ce => ce -> Maybe (Elem ce)
Больше подробностей есть на
wiki.