As people notice, the overlapping instances reveal certain
question about the deduced type contexts.
Consider the example *similar* to one someone recently presented 
(probably, M.Kowalczyk): 

  f :: (Eq a) => Int -> a -> a -> Int
  f n x y =
    if
       n==0  then  0
    else           if  x==y  then  n  else  f (n-1) [x] [y]

  main = let  r = f 100 True False  in  putStr $ shows r "\n"

r  forces to compute (==) on the types like  [[[[[[[[[[[Bool]...],
though, the source program contains only 4 occurrences of `]'.
Further, adding to the scope

  instance Eq [[[[[[[Bool]]]]]]] where x==y = (length x)==(length y)

overlaps with the standard  instance Eq a => Eq [a] ...
and causes, in the existing implementations, many error reports - 
until the user satisfies everything by typing

  f :: (Eq a,Eq [a],Eq [[a]],Eq [[[a]]],Eq [[[[a]]]],
        Eq [[[[[a]]]]],Eq [[[[[[a]]]]]],Eq [[[[[[[a]]]]]]]
       )
       => Int -> a -> a -> Int
  f = ... 
And here, naturally,  main = 93, unlike in the single instance case.

As it was said, this is the simplest way to preserve the correct 
treating of overlapping instances.
Note: 
* adding only  Eq [[[[[[[a]]]]]]]  would not suffice
* if the extra instance shows                             n  
  brackets, the forced type context has to contain about  (n^2)/2  
  of them.
Such a program looks rather awkward.

I propose for the user to remain with `Eq a =>'.
Let the compiler itself deduce and add the needed context.
Maybe, it worths to call it  deduced context.
That is the compiler starts with the sort of "error correcting".
The idea is to save the expression size in the typing of the source
program.
But as Fergus Henderson writes, this is against shared libraries. 
Trying to interpret Fergus's objection, I consider an example.
Let the above  f          be in the module  F,  
instance Eq [..[Boll]..]     in the module  E.
And consider the following projects PP, PP'.
PP  consists of  F  and other modules  M,N  that import  F,
    F.f  has the context `Eq a =>',
The *source* of  M,N  is not given - they form the shared library
(if I call this correctly).  

PP'  adds  E  to  PP  and  `import E'  to  F,  
     and  E  is visible only from  F.
Then,  E  is compiled,  F  is re-compiled, the context of  F.f  
extends with the deduced part, interface changes, and the library 
M,N  would not link to  PP'.

The whole effect: 
overlapping instances tend to need the deduced contexts, 
and the deduced contexts cause that inserting `import E' in  F 
destroys the linkage with the object library importing  F.

Way out:  provide the compilation key  -deduceContext.
-------
This key is for a programmer that uses the overlapping instances
and does not aim the program to link to libraries provided 
without sources.

Sometimes, indeed, the programmer has a task to re-implement  F
preserving the export interface of  F.
But very often this restriction is not required.

----------
Also there is a curious point in the implementors terminology.
They consider the contexts like
                               (Eq a, Eq (a,a), Eq [a], Eq [[a]]) =>

as normal and regular for the *user* program!
And then, they discuss when and how such a context can be reduced by
the compiler.
And according to the user's common sense,  Eq a =>  
has to be considered as initial and regular, keeping in mind that 
there are *infinitely* many statements, like  Eq [[a]],  that can be 
derived logically and trivially from  Eq a,  according to the 
instances in scope.
And then, the *implementor* (not the user) could think what the 
nasty reasons may force the compiler to extend explicitly the
context with the deduced statements. 

------------------
Sergey Mechveliani
[EMAIL PROTECTED]




Reply via email to