From: "Jeffrey Yasskin" <[EMAIL PROTECTED]>
On 8/20/06, John Hughes <[EMAIL PROTECTED]> wrote:
From: "Jon Fairbairn" <[EMAIL PROTECTED]>
> To
> reinforce what Aaron said, if a programme works now, it'll
> still work if map suddenly means fmap.
Well, this isn't quite true, is it? Here's an example:
class Foldable f where
fold :: (a -> a -> a) -> a -> f a -> a
instance Foldable [] where
fold = foldr
example = fold (+) 0 (map (+1) (return 2))
example has the value 3 (of course), but if you replace map by fmap then
the
code no longer compiles.
There's a proposal
http://hackage.haskell.org/trac/haskell-prime/wiki/Defaulting that
mentions extending defaulting to other typeclasses. That seems to fix
this particular problem, but above you mentioned that this was "a
whole new can of worms." Could you elaborate or point me to a
discussion of the worms?
Well, that proposal doesn't cover exporting defaults from modules. If
beginners are not to need to write a default declaration in their own
module, then we would need either to import the right default from the
Prelude, or to have a default default for Monad and Functor, just as we have
for numeric classes today. Importing defaults raises questions over how and
when one can override an imported default with a different default within
one's own module.
The big problem with extended defaulting, though, is ambiguity. The proposal
above includes an example:
default A (Int, String, ())
default B (String, Int, ())
suggesting that a type in both classes should be defaulted to (), because
this is the "first unambiguous type". That isn't a formal definition, and I
actually have difficulty conceiving of a formal definition that would lead
to this result. Even given such a thing, it would have very odd
consequences: presumably if the first line read default A (Int,()), then Int
would now be the first unambiguous type, and thus the chosen default. That
means that removing a default *that was not chosen* would change the
behaviour of the program! I wouldn't like to have to explain THAT to
anybody!
But this simple example of ambiguity is really the least worm in the can.
What about subclassing? Presumably a class default should also apply to its
subclasses... yet at times, we certainly want to override a previous default
in a subclass (e.g. Num and Floating). How should defaulting interact with
context reduction? Imagine a default C (String), and an instance definition
instance C a => C [a]. If we see a C [b], should we apply the detault at
once, instantiating b to Char, or after context reduction, instantiating b
to String? How should defaulting interact with functional dependencies?
Given a bidirectional fundep class C a b | a->b, b->a, then defaults on a
and b separately can conflict. Worms!
Paul Hudak and I thought about this when Haskell was first designed. We did
come up with a proposal, but the rest of the committee thought it was too
complex for what it bought us, hence it was omitted. Nowadays the class
system is a lot more complicated than it was then--constructor classes,
multi-parameter classes, fundeps--and I'm not terribly hopeful about the
prospects for coming up with a simple and powerful design for defaulting.
John
_______________________________________________
Haskell-prime mailing list
Haskell-prime@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-prime