[Haskell-cafe] a bunch of newbie questions
Brian Hulley
brianh at metamilk.com
Fri Aug 4 08:46:22 EDT 2006
Mark T.B. Carroll wrote:
> Janis Voigtlaender <voigt at tcs.inf.tu-dresden.de> 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
More information about the Haskell-Cafe
mailing list