Haskell - typeclass extension

Viewed 100

I've got a question about type classes. I've got the following code:

import Foreign.C.Types (CDouble, CFloat)

class Floating a => Trigonometry a where

    versin :: a -> a
    versin x = 1 - cos x

    vercos :: a -> a
    vercos x = 1 + cos x

    coversin :: a -> a
    coversin x = 1 - sin x

    covercos :: a -> a
    covercos x = 1 + sin x

    haversin :: a -> a
    haversin x = versin x * 0.5

    havercos :: a -> a
    havercos x = vercos x * 0.5

    hacoversin :: a -> a
    hacoversin x = coversin x * 0.5

    hacovercos :: a -> a
    hacovercos x = covercos x * 0.5

instance Trigonometry CDouble
instance Trigonometry CFloat
instance Trigonometry Double
instance Trigonometry Float

Now my question is: there can be infinite amount of Floating instances, and obviously every single instance of Floating can be an instance of Trigonometry without extra implementation. Is there a way to avoid the explicit instance declarations at the bottom and automatically make all Floating instances become Trigonometry instance too?

Cheers!

3 Answers

For this case, there is probably no need to define a typeclass at all, you can implement these functions as top level functions with a Floating type constraint:

versin :: Floating a => a -> a
versin x = 1 - cos x

vercos :: Floating a => a -> a
vercos x = 1 + cos x

coversin :: Floating a => a -> a
coversin x = 1 - sin x

covercos :: Floating a => a -> a
covercos x = 1 + sin x

haversin :: Floating a => a -> a
haversin x = versin x * 0.5

havercos :: Floating a => a -> a
havercos x = vercos x * 0.5

hacoversin :: Floating a => a -> a
hacoversin x = coversin x * 0.5

hacovercos :: Floating a => a -> a
hacovercos x = covercos x * 0.5

If you want to make a special implementation for a certain Floating type, you can indeed work with a typeclass, but if you implement an instance Floating a => Trigonometry a, you likely will end up with overlapping instances.

For those who are looking for something similar, I figured it out:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}

module Algorithms.Math.Trigonometry where

class Floating a => Trigonometry a where

    versin :: a -> a
    versin x = 1 - cos x

    vercos :: a -> a
    vercos x = 1 + cos x

    coversin :: a -> a
    coversin x = 1 - sin x

    covercos :: a -> a
    covercos x = 1 + sin x

    haversin :: a -> a
    haversin x = versin x * 0.5

    havercos :: a -> a
    havercos x = vercos x * 0.5

    hacoversin :: a -> a
    hacoversin x = coversin x * 0.5

    hacovercos :: a -> a
    hacovercos x = covercos x * 0.5

instance Floating a => Trigonometry a

Language extension magic :)

You don't want Haskell to infer that other types are instances of Trigonometry - that would lead to situations where it was using capabilities on types because it found a typeclass lying around that seemed to apply. For example, you might deliberately omit an Ord instance on a type for which it could easily be inferred because Ord doesn't make sense for that type.

If you want a function to apply to any suitable type, you simply remove the typeclass.

Related