'Combine inductive typeclasses

I have a permutation types with has a fixed sizes. Now permutations form a group so I would like to make them an instance of a Group class. Semigroup is easy enough:

instance
  ( Integral i
  )
    => Semigroup (Permutation n i)
  where
    (<>) = ...

However when I get to Monoid I'm a bit stuck. I can't seem to make mempty polymorphic on n. For (<>) the type information of the size of the output was provided as a part of the input, but for mempty there is no input.

What I can do is define the class in terms of induction.

instance
  ( Integral i
  )
    => Monoid (Permutation Zr i)
  where
    mempty = ...

instance
  ( Integral i
  , Monoid (Permutation n i)
  )
    => Monoid (Permutation (Nx n) i)
  where
    mempty = ...

But this is not quite the same. For example if I do the following with Semigroup:

test ::
  ( Integral i
  )
    => Permutation n i -> Permutation n i -> Permutation n i
test =
  (<>)

It compiles just fine, but if I do the following with Monoid:

test ::
  ( Integral i
  )
    => Permutation n i
test =
  mempty
    • Could not deduce (Monoid (Permutation n i))
        arising from a use of ‘mempty’
      from the context: Integral i
        bound by the type signature for:
                   test :: forall i n. Integral i => Permutation n i
    • In the expression: mempty
      In an equation for ‘test’: test = mempty
    |
123 |   mempty
    |   ^^^^^^

Because we cannot infer that Permutation n i is always a Monoid. Even more troublesome is that if I try and take my Monoid instance and make a Group instance, I need to split that in two as well, since Group (Permutation n i) would require Monoid (Permutation n i) which cannot be inferred.

This is less than desirable. I would like to just have 1 instance for Monoid and Group, just like I have for Semigroup.

Is there some way to define a single complete monoid instance? It seems like there might be I just can't think of it.


The definition of permutation is just a wrapper around a type level vector:

newtype Permutation n a =
  Perm (Vector n a)

data Vector n a where
  EmptyVec :: Vector Zr a
  (:++) :: a -> Vector n a -> Vector (Nx n) a

But really I'm interested in a general mechanism that would allow me to make a polymorphic object.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source