Beta Reduction, undefined vs Type Classes

Consider:
class Thing t where thing :: t
instance Thing Int where thing = 0
instance Thing Char where thing = 'a'
Can someone please explain why
fst (1,thing)
...gets an 'ambiguous type variable' error, but
fst (1,undefined)
...doesn't? And is there anything I can change to make the former work as well? Even modifying fst doesn't work:
fst' :: Thing b => (a,b) -> a fst' (~a,~b) = a
--
~ Jared Warren

Jared Warren wrote:
Consider:
class Thing t where thing :: t
instance Thing Int where thing = 0
instance Thing Char where thing = 'a'
Can someone please explain why
fst (1,thing)
...gets an 'ambiguous type variable' error, but
fst (1,undefined)
...doesn't?
Perhaps because "thing" has an ambiguous type (it's either Int of Char), but "undefined" doesn't, (it's for all a.a). Remember that type inference in the Haskell type system does not assume knowledge of the semantics of functions. In order to deduce the type of an application of "fst", you need to determine the type of its argument - you can't discard one of ithe tuple components just because you know you will lose it when you apply a projection function. Type checking is done before any evaulation, compile-time or run-time. You might argue that it would be a good idea to apply some program transformations early to avoid this kind of unnecessary ambiguity, but I have doubts about its general usefullness.
And is there anything I can change to make the former work as well? Even modifying fst doesn't work:
fst' :: Thing b => (a,b) -> a fst' (~a,~b) = a
You should not expect it to work. The problem is with the type ambiguity, not with the semantics of fst. --brian -- Brian Boutel Wellington New Zealand Note the NOSPAM

class Thing t where thing :: t [..] Can someone please explain why
fst (1,thing)
...gets an 'ambiguous type variable' error, but
fst (1,undefined)
...doesn't? And is there anything I can change to make the former work as well? Even modifying fst doesn't work:
This kind of thing is a bit of a "trap for young players". You'll get errors when entering things into the interactive toplevel (hugs/ghci), but if you put it in a program you will almost certainly not get the errors, because more information will be available to the compiler from a full program than from a toy example.
The problem is that the member function "thing" doesn't take anything of type t by which the compiler might infer which instance it is. You can see this even more easily by typing
[]
into ghci.
To fix it, give it a type annotation:
fst (1,thing::Thing Int)
([]::[Double])
for example.
The reason you don't get the error for fst (1,undefined) is because undefined has the perfectly good type (forall a. a), and so (1,undefined) has type (forall a. (Integer,a)) and fst (1,undefined) has type Integer. Polymorphism (like the type of undefined) is much better behaved than overloading (like the types of thing).
It's actually more complicated than this, though - 1 actually has type Num a => a, but Haskell has a built-in "defaulting" rule which says that anything of this type should default to Integer or Double, in that order. So you don't get ambiguity errors for simple numbers. This makes life simpler when using Haskell as a calculator.
HTH.
--KW 8-)
--
Keith Wansbrough
participants (3)
-
Brian Boutel
-
Jared Warren
-
Keith Wansbrough