Mark T.B. Carroll wrote:
Janis Voigtlaender <[EMAIL PROTECTED]> writes:
(snip)
Yes, as long as enough type information is provided for the
typechecker to decide what is the correct instance to use.
(snip)

I've always been a little surprised when this doesn't happen more
widely for things other than instances. For instance, when
IntMap.size, Map.size and Set.size (or whatever) are all in scope as
"size", it should be fairly obvious what (size x) is about once we've
inferred, for other reasons, that x is an IntMap. Similarly with
records, if we had field names that cause functions for extracting
the value of those fields, where we used the same field name in two
different record types, I figure that there's usually no ambiguity
because we can usually infer the type of the object to which the
'extractor' is being applied.

Am I just not seeing the big picture, or would people not find this
use of type information to resolve such ambiguities as nice as I
would, or is it harder to do that than I'm expecting?

I think this is because in Haskell the only way to overload function names is to use type classes and instances just as the one and only way to qualify an identifier is by using modules. This has the advantage that different concerns are clearly separated out and dealt with in exactly one place by one concern-specific mechanism.

Perhaps the basic problem is that (size) really belongs in a type class and IntMap, Set, Map etc were created before anyone bothered to try and factor their portions of common functionality into type classes. This factoring is a non-trivial problem however (as you can see from the various posts on the subject of sequences) since the design space is not nearly as well understood as basic mathematical objects like monoids, monads etc and without a mathematical foundation it is difficult to design a type class factoring with any confidence.

For record fields, I suggested a while back that the compiler could automatically create the relevant type classes and instances eg:

       data Point i = Point {x :: i}

would ensure that a global typeclass was created if not already present:

       class (.x) a b | a -> b where
           (.x) :: a -> b

and would also create an instance for that type:

       instance (.x) (Point i) i where
           (.x) (Point k) = k

where ".x" is parsed as a single lexeme and treated as a postfix operator ie:

       -- no space between '.' and fieldname
       exp .x or exp.x === (.x) exp

but
       exp . x === (.) exp x -- composition

To refer to a particular field name directly you could use:

       g = ((.x) :: Point a -> a)

but I also thought it might be nice to have a special syntax to make things less clunky eg:

       g = Point^x

(It could not be written as Point.x because Point is not a module name, unless you wanted to destroy the very simple rule that Foo.xyz qualifies xyz by the module Foo)

In any case with the trivial syntactic sugar above it would already be possible to use the same record names in multiple types simultaneously. I think the reason there was no positive feedback about this idea before is that unfortunately it looks as if the record system is to be extended to deal with subtyping or horrible anonymous records such as {x=5} that don't have an explicit value constructor in front of them instead of just concentrating on making the existing system (which I really like apart from the lack of field name overloading and dot access syntax) more usable as above.

For value constructors, a change in the type inference algorithm would be needed if they were to be resolved based on their types so you could write eg:

    data Location = Left | Right | Up | Down
    data Hand = Left | Right

    foo :: Location -> Hand
    foo Left = Left
    foo Up = Left
    foo Right = Right
    foo Down = Right

and again there could be a syntax like Location^Left as a less clunky alternative to (Left::Location) in cases where ambiguity needs to be resolved explicitly eg if someone didn't want to write a top level type signature for their function.

Imho this would make life a lot easier because you could concentrate on names that are appropriate to the type without having to know about all the other types you'd want to use unqualified in the same scope.

Regards, Brian.
--
Logic empowers us and Love gives us purpose.
Yet still phantoms restless for eras long past,
congealed in the present in unthought forms,
strive mightily unseen to destroy us.

http://www.metamilk.com
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to