Niklas Vest
Niklas Vest

Reputation: 902

Universally quantified (or polymorphic) type class instances

Is it possible to define a generic type class instance parameterized by a type a in Haskell? For example:

data Box a = Box a deriving Show

class Boxable a where
  create :: a -> Box a

-- pseudo syntax here
instance forall a . Boxable a where
  create = Box

If no, why not?

I am aware of the fact that this example is rather simple and "useless". I just want to know whether this is theoretically possible, not whether its practically relevant.

Upvotes: 2

Views: 134

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120711

Your code is literally legal Haskell, nothing “pseudo syntax” about it. It's not quite Haskell98, but with two very harmless syntactic extensions it does compile:

{-# LANGUAGE ExplicitForall, FlexibleInstances #-}

data Box a = Box a deriving Show

class Boxable a where
  create :: a -> Box a

instance forall a . Boxable a where
  create = Box

The -XExplicitForall is required for the explicit forall (duh), but actually you don't even need this because Haskell type variables are by default universally quantified:

{-# LANGUAGE FlexibleInstances #-}

instance Boxable a where
  create = Box

Except, like chepner already commented this doesn't really make sense, because now create behaves just like a regular parametric function without any typeclass needed:

create' :: a -> Box a
create' = Box

That said, such once-and-for-all instances can actually be useful, if you constrain them with some superclass:

class Foo a
class Bar a

class (Foo a, Bar a) => FooBar a

instance (Foo a, Bar a) => FooBar a

Now if you mention FooBar (someComplicatedType) in a function's constraints, it has the same effect as writing out (Foo (someComplicatedType), Bar (someComplicatedType), which can significantly de-clunk your code and error messages and also make your projects more future-safe, because you can add or remove superclasses to FooBar without changing the signatures of all the functions that have this constraint.

(A very similar thing can be achieved with -XConstraintKinds as the arguably more straightforward constraint synonym type FooBar a = (Foo a, Bar a), but this brings in the well-known problem that type isn't really an encapsulation at all but can be unravelled by the compiler at any time, which isn't normally much of a problem except it leads to much more confusing type error messages.)


You won't find -XExplicitForall itself very often in Haskell files, because it's only really needed as part of either -XScopedTypeVariables or -XRankNTypes, both of which are common and enable the forall keyword, or as I prefer to write it (which additionally requires -XUnicodeSyntax).

Upvotes: 5

Related Questions