How do I make a container for a double a Semigroup?

117 views Asked by At

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.)

1

There are 1 answers

1
leftaroundabout On BEST ANSWER

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.