On Sun, 3 Aug 2003, Derek Elkins wrote: > I kinda think someone mentioned this, perhaps even you. Or maybe I'm > thinking of something else. As I'm feeling too lazy to check the > archives, at the risk of saying something stupid or repeating something > said, you may want to look at named instances (google should turn > something up with a little effort.) It seems to cover some of the > same issues/ideas you are having now, though in a different context.
I found a paper on named instances at http://www.cs.uu.nl/people/ralf/hw2001/4.html Thanks for pointing me to this; it's very interesting. As part of my proposal I was thinking about the possibility of decoupling the typeclass system from implicitness, but there were enough complications that I gave up. But this paper makes it look doable. Given plus :: (Num a) => a -> a -> a, the application plus (1::Int) currently has type Int -> Int. But it could equally well have type (Num Int) => Int -> Int. This type has the advantage of being more versatile: in principle you can supply your own type class. The problem is that usually you want Int -> Int, and it would be terribly cumbersome to have to apply the default Num Int dictionary by hand every time. That's as far as I got. But the paper points out that implicit context reduction in this case is perfectly safe and predictable as long as there's a global default value for the dictionary. Two implicit reductions can't conflict because the value passed implicitly is always the same, and an implicit reduction can't conflict with an explicit one because the explicit reduction changes the type, making the implicit reduction illegal. The paper suggests the notation f # MyInstance, but of course I think it should be something like f { Num Int = MyInstance } or f { MyInstance }. This notation is uglier, but it's more consistent and it avoids stealing a nice short infix operator which people have proposed to use for many other things. This works for named parameters too (explicit and implicit). You could write something like default #name = value or even just #name = value since this introduces no ambiguity if named parameters never clash with ordinary variable identifiers. Then implicit reduction is perfectly safe (in the sense that the behavior is unaffected by type signatures). This is better than the parameter-defaulting scheme I was thinking of. There are some complications, but I think they all have solutions: 1. The default value for #name has to be global to the whole application, so functions in other modules with a named parameter #name will have to use your default. Solution: make parameter names part of the module namespace. 2. You can't have named parameters with the same name but different types, if there's a global default. Solution: Invent a new notation for explicitly typing the defaults (not sure this is possible), or just live with the limitation. Haskell doesn't have Java-style overloading. 3. Problems arise in the case of duplicate dictionary types. Consider f x y = (x+1,y+1) with type (Num a, Num b) => a -> b -> (a,b). Then g = f (1::Int) (2::Int) has type (Num Int, Num Int) => (Int,Int). In the expression g { Num Int = ... }, which typeclass parameter are we applying? The solution, as pointed out in the paper, is to make the typeclass parameters explicit in the definition of f. Then f has type Num a => Num b => ... and g has type Num Int => Num Int => (Int,Int), and the order of application is unambiguous. There are additional subtleties described in the paper which I don't understand yet. -- Ben _______________________________________________ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell