The instance
instance (...) => SumRes (Int -> r) where
roughly means "here's how to define SumRes
on Int -> r
for any r
(under certain conditions)". Compare it with
instance (...) => SumRes (a -> r) where
which means "here's how to define SumRes
on a -> r
for any a,r
(under certain conditions)".
The main difference is that the second one states that this is the relevant instance whichever the types a,r
might be. Barring some (very tricky and potentially dangerous) Haskell extension, one can not add more instances later on involving functions. Instead, the first one leaves room for new instances such as e.g.
instance (...) => SumRes (Double -> r) where ...
instance (...) => SumRes (Integer -> r) where ...
instance (...) => SumRes (Float -> r) where ...
instance (...) => SumRes (String -> r) where ... -- nonsense, but allowed
This is paired with the fact that numeric literals such as 5
are polymorphic: their type must be inferred from the context. Since later on the compiler might find e.g. a Double -> r
instance and choose Double
as the literal types, the compiler does not commit to the Int -> r
instance, and reports the ambiguity in a type error.
Note that, using some (safe) Haskell extensions (such as TypeFamilies
), it is possible to "promise" to the compiler that your Int -> r
is the only one that will be declared in the whole program. This is done like this:
instance (..., a ~ Int) => SumRes (a -> r) where ...
This promises to handle all the "functional type" cases, but requires that a
is actually the same type as Int
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…