[Haskell-cafe] Question about ambiguity and defaulting in recursive bindings

Benjamin Redelings benjamin.redelings at gmail.com
Wed Jan 19 19:19:40 UTC 2022


Hi,

I am trying to understand how GHC treats the following declaration.

f c i   = if i == 10 then c else g c 'b'
g 'a' w = f 'b' 10
g z   w = z

l = (f 'a' (1::Int), f 'a' (1.0::Double))

It seems to me like, after defaulting, f should have the following type:

     Char -> Int -> Char

However, looking at -ddump-tc, GHC is deriving the polymorphic type

     forall a. (Eq a, Num a) => Char -> a -> Char

That's much nicer, because its more flexible.  But I'm confused, because 
it looks like GHC is defaulting 'g', but not 'f', even though they are 
in the same recursive group.  This seems to contradict "Typing Haskell 
in Haskell", which is what I am looking at right now.  If that is 
correct, can anybody point me to a paper or documentation about how this 
works?

More detail:

1. If I understand correctly, the definitions of `f` and `g` are 
mutually recursive, and should be typed together, and the declaration 
group is not restricted.

2. It seems like, before generalization, we have

     f :: Char -> a -> Char
     g :: Char -> Char -> Char
     Predicates include (Eq a, Num a)

3. Looking at the paper "Typing Haskell in Haskell" (THIH), it looks 
like the predicates (Num a, Eq a) should cause an ambiguity in the 
definition of g:

* a is present in the definition of f, but not the definition of g

* so the type (Eq a, Num a) => Char -> Char -> Char is ambiguous.

* more generally, it seems like THIH treats any predicates with a type 
variable that is part of some, but not all, types in the declaration 
group to be ambiguous.  Does this sound right?

4. Then, again following THIH, this ambiguous predicate should be 
defaulted to Int.

I THINK this should lead to

	f :: Char -> Int -> Char
	g :: Char -> Char -> Char

5. However, I'm still not sure I'm understanding this right, because a 
few things still don't make sense:

* First, THIH seems to eliminate the defaulted predicates without 
substituting a -> Int.  But the type for f DOES mention `a`, so how can 
we avoid substituting?

* Second, GHC accepts the code with no warnings or errors. There is some 
kind of defaulting going on, because GHC rejects the code if I add 
"default ()". Is there some way for GHC to default only g, but not f?

I wonder if this involves a difference between Haskell '98 and Haskell 2010?

I also wonder how much I should rely on THIH?  Maybe the language has 
moved on since then?

-BenRI
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20220119/ffafd976/attachment.html>


More information about the Haskell-Cafe mailing list