8

In my Haskell codebase, I have many functions that take polymorphic arguments. These polymorphic arguments all need to satisfy the same set of typeclasses (RealFloat a, Floating a, Real a, Show a, Ord a, Typeable a) and this set of typeclasses needs to be present in the functions' type annotations.

Right now I've been manually writing the typeclass annotations for every function, but it gets verbose to have that list of typeclasses repeated 30+ times in my codebase, and cumbersome to have to change each type annotation if I find out I need to add another typeclass to the list. I'm wondering if there is a more concise way to factor out a common list of typeclasses.

I'm really looking to define a "typeclass synonym" like typeclass NiceFloating a = RealFloat a, Floating a, Real a, Show a, Ord a, Typeable a so I can just write NiceFloating a => a in all of my type annotations instead.

If that feature doesn't exist, perhaps I can write a "master typeclass" that requires that a value satisfy every typeclass in the list of typeclasses? But I don't want to write out all the operations for e.g. Real, Show, and Ord by hand—is there a way around that?

kye
  • 443
  • 3
  • 8

1 Answers1

12
{-# LANGUAGE ConstraintKinds #-}
type NiceFloating a = (RealFloat a, Floating a, Real a, Show a, Ord a, Typeable a)

This defines the wanted NiceFloating :: * -> Constraint.

chi
  • 111,837
  • 3
  • 133
  • 218
  • 1
    It's not quite `* -> Constraint`, since it's just a synonym, so it can't be used as a first-class entity with that kind. Fine for this question, but if any more structure is needed, use the idiom `class (RealFloat a, Floating a, ...) => NiceFloating a; instance (RealFloat a, Floating a, ...) => NiceFloating a`, which can be used in a higher-order way. – luqui Feb 06 '18 at 08:31
  • 3
    I'd also upgrade it to a class. A constraint synonym can reduce repetition there too. `type NiceFloating' a = (...); class NiceFloatingC a => NiceFloating a; instance NiceFloatingC a => NiceFloating a`. Kind of ugly, but works when you need to pass the `NiceFloating` around. – dfeuer Feb 06 '18 at 08:33
  • @luqui True, it's not quite it, yet `:k` in GHCi pretends it is `* -> Constraint`. – chi Feb 06 '18 at 09:08
  • 1
    Also, with `-XLiberalTypeSynonyms`, such a typesyn _can_ be used in some settings that would otherwise require a proper class. – leftaroundabout Nov 10 '18 at 13:40