I'm (relatively) new to Haskell and want to code some math. For example, abelian groups. I would like to write the following code:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
module Structures where
class Eq g => AbelianGroup g where
type family AbelianGroupElement g = e | e -> g
add :: AbelianGroupElement g -> AbelianGroupElement g -> AbelianGroupElement g
inv :: AbelianGroupElement g -> AbelianGroupElement g
unit :: g -> AbelianGroupElement g
parent :: AbelianGroupElement g -> g
data Z = Z deriving Eq
data ZElement = ZElement Z Int deriving Eq
instance AbelianGroup Z where
type instance AbelianGroupElement Z = ZElement
add (ZElement z1 x1) (ZElement z2 x2)
| z1 == z2 = (ZElement z1 (x1+x2))
| otherwise = error "elements from different groups"
inv (ZElement z x) = (ZElement z (-x))
unit z = ZElement z 0
parent (ZElement z x) = z
data ProductAbGrp g1 g2 =
ProductAbGrp g1 g2 deriving Eq
data ProductAbGrpEl g1 g2 =
ProductAbGrpEl (ProductAbGrp g1 g2) (AbelianGroupElement g1) (AbelianGroupElement g2) deriving Eq
Compiling the above gives me the error
No instance for (Eq (AbelianGroupElement g1))
arising from the second field of `ProductAbGrpEl'
(type `AbelianGroupElement g1')
This makes sense; I haven't ensured that (AbelianGroupElement g1) always has Eq defined for it. However, I'm not sure how I can accomplish that. I can change the above to
{-# LANGUAGE FlexibleContexts #-}
...
class (Eq g, Eq (AbelianGroupElement g)) => AbelianGroup g where
but this doesn't help. (It's possible that type families are the wrong way to go here; I originally started with MultiParamTypeClasses and FunctionalDependencies, but had other issues with that and got the impression that type families were better).
Thanks for reading this; any help would be appreciated.
You can use
StandaloneDerivingto get basically what you want, although I admit it's not as pretty as simply writingderiving Eq: