When calling the following, GHCI returns an error: Ambiguous type variables ‘f0’, ‘b0’ arising from a use of ‘print’ prevents the constraint ‘(Show (f0 b0))’ from being solved.
From what I understand, this is because the type of my Expression is (Num b, Functor f) => [f b] where f is the ambiguous type.
However, the Functor instance of List defines fmap as map, and the definition of map ignores the function argument in case the second argument is [] to simply return []. This should mean that my expression should simply return [] regardless of how many fmap compositions I apply, and a call to show [] should go through. Why is it that I see the error then?
(fmap.fmap) (+1) []
It is true that your function will always return []
, but typeclass dispatch (which happens at compile-time, rather than run-time) must be based on the type of the argument to show
. The Show
instance for [a]
requires that Show a
also be resolved (instance Show a => Show [a]
)---since there are many values of type [a]
which do contain elements---and since the type of the list elements (all 0 of them) is ambiguous, the Show
constraint can't be resolved.
This might lead you to ask why show []
for example does not have the same issue, since [] :: [a]
. The answer here is that GHCi has some special Extended Default Rules heuristics, which apply in certain simple cases, in order to make working at the prompt more pleasant. If you :set -XNoExtendedDefaultRules
you can see that show []
will have this same behavior. In your case, since the element type of the list is f0 b0
rather than a single type variable, the linked extended defaulting rules do not apply, and so the list element type still contains ambiguous type variables.
You can see that this is the issue by resolving some of the type constraints yourself, say by using -XTypeApplications
. Even resolving the Functor
constraint is enough to make the normal Haskell type defaulting rules apply again: (fmap.(fmap @[])) (+1) []
does indeed print []
at the GHCi prompt.