This is pure speculation, inspired in part by Brent Yorgey's blog
post[1] from a few weeks ago.
I'm wondering if it might be possible, in theory, to have both open
and closed variants for each of value-level functions, type functions,
and classes, in a fairly analogous way. (Maybe you could even have
open (G)ADTs, which you would then need open functions to match on; or
maybe a closed one with a case for _ to ensure exhaustiveness.)
In each case you'd have the closed variant requiring you to keep all
the definitions in the same module, permitting overlap, and trying to
match definitions in the order they're listed; whereas the open
variant would let you have definitions across modules, would forbid
overlap (or would require definitions to be equivalent where they
overlap, as with type families), and would always select the uniquely
matching definition.
Open value-level functions with this scheme would be inherently
partial, which is bad. (It's not a problem at the type level because
you just get a compile error if nothing matches, but an exception at
runtime isn't so nice.) As a solution, perhaps it might be possible to
allow a limited form of overlap (or don't even call it overlap) for
the open variants: a default "use this is if nothing else matches"
definition (which would need to be in the same module as the original
class / type family declaration, or whatever ends up being analogous
for open value-level functions, maybe the type signature). That way
you could use Maybe for open value-level functions and make the
default Nothing, among other options. Overlap in type functions
allegedly makes typechecking unsound; I don't know if that would also
hold in this more limited case. This would definitely break the
property where adding or removing an import can't change the behaviour
of a program other than whether it compiles, which is considered very
important by many [2], so maybe it's not a good solution. (Possibly
you could add explicit import/export control for
instances/other-open-things to alleviate this, in a way so that
definitions for open thingies with default definitions (at least)
would always have to imported explicitly, thereby acknowledging that
it might change behaviour... or maybe that would be a bandaid too far,
I dunno.)
(I think this would also cover most (if not all?) of the use cases for
OverlappingInstances, which permits overlap and selects the most
specific instance in a more general fashion; but maybe that doesn't
matter if the two are equally bad, I don't know. I'm not 100% clear on
peoples' opinion of OverlappingInstances, but I as far as I know the
problems are twofold: both import-unsafeness, and the matter of how
you would actually define "most specific" in a way that's both
rigorous and intuitive; this would remove at least the latter.)
Anyway, thoughts? Is this all completely crazy and way out there?
[1] http://byorgey.wordpress.com/2010/08/05/typed-type-level-programming-in-haskell-part-iv-collapsing-types-and-kinds/
[2] http://hackage.haskell.org/trac/haskell-prime/wiki/LanguageQualities
--
Work is punishment for failing to procrastinate effectively.