Reputation: 69934
While I know that there is a TypeSynonymInstances extension in GHC, I have no idea how "dangerous" it is and I wonder if this restriction is arbitrary, kind of like the Monomorphism Restriction, or if there are deeper reasons for it.
Upvotes: 36
Views: 8420
Reputation: 23014
It used to be allowed, but in attempt to make Haskell less full of surprises to beginners it was banned.
Upvotes: 6
Reputation: 139850
TypeSynonymInstances
is perfectly safe. Since anything potentially fancy like partially applied type synonyms is disallowed, it has exactly the same effect as typing out the the right hand side of the type synonym in the instance head, i.e.
type Foo a = ([a], [a])
instance Bar (Foo a)
is the same as
instance Bar ([a], [a])
However, note that both instances require FlexibleInstances
since they contain nested type constructors as well as repeated type variables. In general, this will often be the case after expanding type synonyms.
I think may be the reason why they're disallowed by default.
However, FlexibleInstances
is also a perfectly safe extension. The worst it can do is cause a compile-time error if you try to define overlapping instances such as
instance Xyzzy String
instance Xyzzy [a]
As for why FlexibleInstances
is not available by default, I can only guess that it's to simplify the language. The standard rules for instance heads ensures that the only way instance definitions can overlap is if the type constructors in the instance heads are identical, while with FlexibleInstances
checking for overlaps is slightly more difficult.
Upvotes: 31
Reputation: 36622
As I understand it, it's sort of like the monomorphism restriction—there's nothing wrong about getting rid of it, but it opens you up to behavior you might not expect. Just like the monomorphism restriction doesn't hurt anything—all the types are still valid—this also ought to be totally safe: there are restrictions on type synonyms anyway which prevent them from doing anything fancier than simple name shortening (e.g., you can never partially apply them, so we don't get type-level lambdas), and so you can always replace them with the right-hand side of their definition. Thus, since the right-hand sides of those definitions can be checked as instance heads (or contain further type synonyms to expand out), nothing unsafe should be going on.
On the other hand, just as disabling the monomorphism restriction opens you up to potentially odd performance characteristics, enabling type synonym instances opens you up to potentially odd type class errors. So let's enable -XTypeSynonymInstances
and try writing an instance with a type synonym:
Prelude> :set -XTypeSynonymInstances
Prelude> instance Num String where (+) = (++)
<interactive>:3:10:
Illegal instance declaration for `Num String'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Num String'
String
looks like a plain old type, so this might be surprising at first; but it's really [Char]
, and so this instance is invalid according to Haskell 2010's strict rules. If we relax those rules by turning turn on -XFlexibleInstances
(which, incidentally, implies -XTypeSynonymInstances
), this example works now:
Prelude> :set -XFlexibleInstances
Prelude> instance Num String where (+) = (++)
... errors about undefined methods ...
Prelude> "a" + "b"
"ab"
But things gets ugly fast:
Prelude> instance Eq String where
Prelude> "a" == "b"
<interactive>:8:5:
Overlapping instances for Eq [Char]
arising from a use of `=='
Matching instances:
instance Eq a => Eq [a] -- Defined in `GHC.Classes'
instance Eq String -- Defined at <interactive>:7:10
In the expression: "a" == "b"
In an equation for `it': it = "a" == "b"
Again, even though String
looks like a distinct type, we already have an instance for [a]
, and so this overlaps with it. (And in fact, this is probably part of why -XFlexibleInstances
isn't on by default.) And turning on -XOverlappingInstances
is a much dodgier idea than turning on -XFlexibleInstances
.
Upvotes: 18