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?