When using MultiParamTypeClasses, do you need to use every type in every class function

haskell

Solution

If not, shouldn't the compiler forbid me from ever creating a class function that doesn't use all type parameters?

Perhaps. Indeed you'll never be able to use such a class method. But as the error occurs always at compile-time, it's not really dangerous.

Fixes that work in some similar cases (not in yours, though):

Make the undetermined type variable functionally dependent on one of the others.

{-# LANGUAGE FunctionalDependencies #-}
class Group_FD g p | g->p where
  identity :: g

This could be used perhaps like

data Nat = One | Succ Nat

instance Group_FD Nat Mult where
  identity = One

instance Group_FD Int Add where
  identity = 0

But it's obviously not possible to make multiple instances with the same `g` element this way.

Define a seperate class with only one parameter for the methods that depend only on that. Then make this class a constraint ("superclass") on the other one, to "import" methods:

class Identity i where
  identity :: i
class (Identity i) => Test i y

that's no use at all for your application though, since you want the behaviour of `identity` to depend on the Phantom type variable.

To achieve your goal, you must somehow pass the information of which instance you want. One way to achieve this is phantom arguments:

class Group_PA g p where
  identity :: p -> g

instance Group_PA Int Add where
  identity _ = 0

instance Group_PA Int Mult where
  identity _ = 1

You could then use that like

GHCi> identity Add :: Int 0 GHCi> identity Mult :: Int 1

Perhaps more idiomatic would actually be to make the flag types empty

{-# LANGUAGE EmptyDataDecls #-}
data Add
data Mult

GHCi> identity (undefined :: Add) :: Int 0 GHCi> identity (undefined :: Mult) :: Int 1

This makes it clearer that the phantom argument actually carries no runtime information, just controls what instance the compiler chooses.

Admittedly, this is pretty ugly.

The right™ solution is to make newtype wrappers to contain the phantom information. In fact, such wrappers are already in the standard libraries: `Sum` and `Product`.

Problem

When I use MultiParamTypeClasses, I can create class functions that ignore one of the type parameters (ie- like "identity" below). ``` {-# LANGUAGE MultiParamTypeClasses #-} data Add = Add data Mul = Mul class Test a b where identity::a instance Test Int Add where identity = 0 instance Test Int Mul where identity = 1 ``` (this is a stripped down version, of course in the full program there would be other functions that would use "b"). The example compiles, but I can never access identity! ``` main = do putStrLn (show (identity::Int)) ``` leads to "No instance for (Test Int b0) arising from a use of 'identity'. Is there a way to access identity? If not, shouldn't the compiler forbid me from ever creating a class function that doesn't use all type parameters?

Original source