1
votes

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) []
1
Because in order to render it a list, the type constraint is that it should render the elements. The instance is instance Show a => Show [a].Willem Van Onsem
Thanks, that makes sense. Does this mean that if I were to write a function functorExample :: [[Int]] -> [[Int]] in which functorExample = (fmap.fmap) (+1), the ambiguous types f0 and a0 get resolved to valid instances i.e. [] and Int?user4132
indeed, you can try (fmap . fmap) (+1) [] :: [[Int]], and it will print [].Willem Van Onsem

1 Answers

5
votes

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.