Confusion about the order of constraints and type variables in a signature (aka. `forall a. a -> Eq a => a` is valid)

I was recently surprised to find that the following three signatures are all valid:

isEqual :: forall a. Eq a => a -> a -> Boolean
isEqual x y = x == y

isEqual' :: forall a. a -> Eq a => a -> Boolean
isEqual' x y = x == y

isEqual'' :: forall a. a -> a -> Eq a =>  Boolean
isEqual'' x y = x == y

I couldn’t find any documentation about this behavior and I was wondering if anyone could explain it to me. I see that psci seems to retain the original signatures:

> :t isEqual
forall (a :: Type). Eq a => a -> a -> Boolean

> :t isEqual'
forall (a :: Type). a -> (Eq a => a -> Boolean)

> :t isEqual''
forall (a :: Type). a -> a -> (Eq a => Boolean)

Is this some sort of feature or just a grammar quirk? Thanks!

It’s not a grammar quirk. For terms, when you see a type with =>, this is a unary function where the argument (of kind Constraint, rather than the usual Type for ->) is implicitly provided by the compiler.


Consider the following:

data Foo = Foo
f = isEqual Foo
g = isEqual' Foo

f is an error but g is not; see if you can understand why.

1 Like