Type unification with multi-parameter type classes
haskell
Solution
I can tell you why the first one doesn't work.
`Coerce` could potentially be defined for any possible pair of types. `coerce 0 :: Int` is parsed as `(coerce 0) :: Int`. So you've fixed the `b` in `coerce :: a -> b` with the type annotation, but not the the `a`.
Numeric literals are polymorphic, so `0` has type `Num a => a`. That won't work; there's no instance matching `Coerce a Int`. There could be `Coerce Double Int`, `Coerce Complex Int`, etc, so knowing that `b` is `Int` isn't enough to infer that that `0` is an `Int`. We'd need to say `coerce (0 :: Int) :: Int` to fix both type parameters.
I believe the second one works because constraints on the instance declaration aren't used to help resolve type classes. `instance a ~ b => Coerce a b` is matched exactly as if you'd written `instance Coerce a b`. I.e. this is the most general instance possible (for the purpose of type class resolution), which well match any possible call to `coerce` (and so you can't write any other non-overlapping instances). The `a ~ b` constraint is only applied after the instance is chosen.
Since you have one instance that matches anything, there's no problem selecting an instance for `coerce 0 :: Int`, even though we still have the same problem of not knowing what type the `0` is. But then after instance selection, we now have the additional constraint `a ~ Int`, which allows unambiguous types to be assigned to everything.
Problem
``` {-# LANGUAGE MultiParamTypeClasses #-} class Coerce a b where coerce :: a -> b instance Coerce a a where coerce a = a ``` Now, this won't work: `coerce 0 :: Int` But if the instance is replace with this, the expression works: ``` instance a ~ b => Coerce a b where coerce x = x ``` Why?