Is there some way of preventing the type mechanism from generating code for the instance type, as opposed to the class?
I don't understand this question - does the explanation above help?
I could have been clearer with my questions. What I was wondering was: is there some situation where the compiler can't statically determine the type to be used?
The function "double" will work on any type in the class Num, so the compiler can't know which "+" function to use.
When it's applied, the compiler will know the types of the arguments, won't it?. Which means that you would generate a version of double for each (applied) instance of Num. I don't doubt that there's a good reason this is not done: code bloat? or are there simply some expressions that can't be statically resolved? I suppose I was thinking: is the language design sufficiently clever that it's *always* possible for the compiler to infer the type instance in use, or are there some situations where it's not possible to infer the instance, so some kind of function dispatch mechanism is necessary?
Yes, roughly. In Haskell, the compiler always figures out the types of everything at compile time. This means it can often figure out which bit of code to use at compile time as well - but because of polymorphism, not always. Consider this bit of code:
double :: Num a => a -> a double x = x + x
The function "double" will work on any type in the class Num, so the compiler can't know which "+" function to use. But it *doesn't* solve this by run-time dispatch, like in C++. Instead, it compiles double like this:
double' :: NumDict a -> a -> a double' d x = let f = plus d in x `f` x
where NumDict is a record a bit like this:
data NumDict a = NumDict { plus :: a -> a -> a, minus :: a -> a -> a, fromInteger :: Integer -> a ... }
NumDict is called a "dictionary", and any time double' is called, the caller must supply the right dictionary. If you write
double 2.0
then the compiler sees that you've written a Double, and so supplies the NumDict Double dictionary:
double' doubleNum 2.0
where doubleNum :: NumDict Double contains the methods for adding Doubles, subtracting them, and converting from Integers to them.
This looks like a dispatching mechanism to me. However, I think I see that this can still be done at compile-time. When double is applied to 2.0, the compiler generates the double' doubleNum 2.0 code, which is still statically resolvable. The advantage seems to be that you don't generate a double function for each Num instance. Does this also mean that a dictionary class is created for every class, and a dictionary created for every instance?
Getting back to your original question, there's a little subtlety in Haskell to do with literals. Whenever you type an integer literal like "2", what the compiler actually sees is "fromInteger 2". Another little subtlety called "defaulting" (see the Haskell 98 Report, in section 4.3.4) arranges that in this
I knew about the "fromInteger" and similar treatment of literals, but the defaulting system is news to me. I've skimmed over the Haskell report, but details like this never sink in until you encounter them in practice...
Instance exporting is not easy to control in Haskell; if you export a type, then all its instances are exported along with it automatically.
Thanks. I wasn't sure how the export mechanism worked with regard to classes and instances; I just took a (wrong) guess that you could control export of classes and types separately. ***************************************************************** The information in this email and in any attachments is confidential and intended solely for the attention and use of the named addressee(s). This information may be subject to legal professional or other privilege or may otherwise be protected by work product immunity or other legal rules. It must not be disclosed to any person without our authority. If you are not the intended recipient, or a person responsible for delivering it to the intended recipient, you are not authorised to and must not disclose, copy, distribute, or retain this message or any part of it. *****************************************************************
Bayley, Alistair wrote:
When it's applied, the compiler will know the types of the arguments, won't it?. Which means that you would generate a version of double for each (applied) instance of Num. I don't doubt that there's a good reason this is not done: code bloat? or are there simply some expressions that can't be statically resolved?
I suppose I was thinking: is the language design sufficiently clever that it's *always* possible for the compiler to infer the type instance in use, or are there some situations where it's not possible to infer the instance, so some kind of function dispatch mechanism is necessary?
This almost is an FAQ. Short answer: in general it is impossible to determine statically which instances/dictionaries are needed during evaluation. Their number may even be infinite. The main reason is that Haskell allows polymorphic recursion. Consider the following (dumb) example: f :: Eq a => [a] -> Bool f [] = True f (x:xs) = x == x && f (map (\x -> [x]) xs) The number of instances used by f depends on the length of the argument list! Determining that statically is of course undecidable. If the list is infinite, f will use infinitely many instances (potentially, depending on lazy evaluation). Another (non-Haskell-98) feature that prevents static resolution of type class dispatch are existential types, which actually provide the equivalent to "real" OO-style dynamic dispatch. Of course, for most practical programs, the optimization you have in mind would be possible. I doubt compilers generally do it globally, though, because it requires whole program analysis, i.e. does not interfer well with separate compilation (beside other reasons). | Andreas -- Andreas Rossberg, rossberg@ps.uni-sb.de "Computer games don't affect kids; I mean if Pac Man affected us as kids, we would all be running around in darkened rooms, munching magic pills, and listening to repetitive electronic music." - Kristian Wilson, Nintendo Inc.
Does this also mean that a dictionary class is created for every class, and a dictionary created for every instance?
Yes, exactly. Every class is translated to a data type declaration, and every instance is translated to an element of that data type - a dictionary. (Note that you can't actually write those declarations in Haskell 98 in general, because they can have polymorphic fields; but this is a simple extension to the language). Take a look at one of the references Bernard put on the bottom of the Wiki page I just created for further information. http://www.haskell.org/hawiki/TypeClass --KW 8-)
participants (3)
-
Andreas Rossberg -
Bayley, Alistair -
Keith Wansbrough