I am learning Haskell. Imagine I have the following:
data Coordinate = Coordinate double
I wish to implement a semigroup instance for Coordinate
.
instance Semigroup (Coordinate a) where
Coordinate a <> Coordinate b = Coordinate (a b)
The typechecker is displeased at me:
• Expected kind ‘* -> *’, but ‘Coordinate’ has kind ‘*’
• In the first argument of ‘Semigroup’, namely ‘(Coordinate a)’
In the instance declaration for ‘Semigroup (Coordinate a)’
|
175 | instance (Num a) => Semigroup (Coordinate a) where
(I know that this is just an empty container for a double and I could already be using just the double itself, but I am learning Haskell and I would like to understand how this works.)
CodePudding user response:
The way you specified Coordinate
, it doesn't have any type parameters. So the semigroup instance head should be simply
instance Semigroup Coordinate where
...
Alternatively, you can give it a parameter to allow including different number types:
newtype Coordinate' a = Coordinate' { getCoordinate' :: a }
In this case, the Semigroup
instance will need to mention the parameter, however just calling it a
won't be enough because you can't perform
on arbitrary types. You need to either restrict it to Double
there
instance Semigroup (Coordinate' Double)
or to an arbitrary numerical type
instance Num a => Semigroup (Coordinate' a)
Note that in either case, Semigroup
may not be the best class for the purpose, consider using AdditiveGroup
and then you can also make it a VectorSpace
.