When writing contexts on a type signature, ordinarily I would do something like
f :: (Enum a, Ord a) => a -> a
But through sheer dumb luck I found that this compiles and seems to work identically, at least on GHC 7.8:
f :: Enum a => Ord a => a -> a
What are the theoretical or practical differences between the two? Is the second one less orthodox? The Haskell report seems to make no mention of the second form, and I've never seen it used anywhere. Related question.
The two versions are the same. Constraints and forall
-s are floated out to the top of the scope when they are not already there. For example, the following definitions are valid:
foo :: a -> a -> Num a => a
foo = (+)
bar :: a -> forall b. b -> a
bar = const
But :t foo
prints Num a => a -> a -> a
and :t bar
prints a -> b -> a
(which is equivalent to forall a b. a -> b -> a
).
GHC doesn't support polymorphic return types, that's why the constraints and quantifiers are floated out. I guess it could have been also a valid design choice for GHC to throw errors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With