
Subject: Re: Export lists in modules
Type signatures currently do more than state the type of a variable. They potentially (i) enable polymorphic recursion, and (ii) disable the monomorphism restriction, thus losing sharing. It would be very strange if a type signature *in an export list* were to have these effects--the export list surely should not change the way a module is compiled and type-checked. One good principle is that commenting out the export list should not change the way any definition is compiled, only what is exported. After all, commenting out the exports (so that all definitions can be tested) is a common step when debugging a module. I would conclude that polymorphic recursion should be enabled only if a type signature appears *in the body of the module*, similarly the M-R should be disabled only if an overloaded type signature appears in the body of the module. The same principle should apply to any other type signatures that change the way a definition is type-checked, if they are included in Haskell', such as rank-2 or rank-N type signatures. John

John Hughes wrote:
Type signatures currently do more than state the type of a variable. They potentially (i) enable polymorphic recursion, and (ii) disable the monomorphism restriction, thus losing sharing. It would be very strange if a type signature *in an export list* were to have these effects--the export list surely should not change the way a module is compiled and type-checked.
This reminds me of the days when I still used OCaml: In particular of my frustration that the interface was NOT used while compiling, so I had to add type annotations to the implementation (and use a syntax that was different from the interface syntax, so I couldn't just relegate it to FunnelWeb-as-duplication-avoiding-preprocessor which I used anyway to eliminate the duplication of exported data type implementations necessitated by the module system there). In Haskell, as it stands, and as John explained, a veriable type signature already DOES influence type checking and compilation of the code used to define the implementation of that variable. Why should a module type signature NOT influence type checking and compilation of the code used to define the implementation of that module?
After all, commenting out the exports (so that all definitions can be tested) is a common step when debugging a module.
This is a good pragmatic argument. But the functionality could also be achieved in different ways --- perhaps by allowing an overlapping ``module CurrentModule'' in the export list. And while we are at this argument, another debugging hurdle are local functions --- frequently one has to make them global to be able to test them (and then forgets to make them local again...). It would of course be nice if we could test local functions, too, so if I define
f x 0 = 1 f x y = fff f g x y where g z = ggg f g x y z
I would like to call interactively something like < f#g x y z and have this effectively call < ggg f g x y z whithout the need to make ggg global. This is essentially the same problem as
commenting out the exports (so that all definitions can be tested) is a common step when debugging a module
, namely gaining access to hidden entities. An even more notorious example of hidden entities in Haskell are the functions used to define functors: The usual way to define, e.g.,
instance Show a => ShowS [a] where showsPrec p (x:xs) = .... p ... showsPrec 0 (x :: a) ...
includes the definition of a function that cannot be accessed. It is the function showsPrecList in the following:
instance Show a => ShowS [a] where showsPrec = showsPrecList showsPrec
type ShowSPrec a = Int -> a -> ShowS
showsPrecList :: ShowSPrec a -> ShowSPrec [a] showsPrecList showsPrecElem = ...
Not only is there no easy way to debug the implicitely defined version of functions like showsPrecList; these functions tend to be very useful in more general contexts. Therefore I keep suggesting to make a habit of using the above pattern to define instances with contexts. Should we provide a language feature that even with the ``traditional'' instance declaration gives us access to this anonymous function? (Would be quite complex... ) (If not, I would at least like to have those functions exported by all standard library modules --- I had to redefine a whole bunch of them... ) We also would need a name for the instance in the first place... ;-) An easy way out would be to declare this primarily not a language design problem, but rather a support tool problem... However, the ease with which Haskell hides away perfectly re-usable material does lead to a lot of code duplication --- I mentioned functions like showsPrecList (and, much much worse, readsPrecList) that probably not only I had to re-implement because they are not exported from the standard libraries --- not because they are concsiously hidden, but because the current language design encourages a concise style to provide access to a specialised instance of these functions, hiding away the more general version which is however already present in the code. Similarly, many local functions embody re-usable material, but we frequently do not take the trouble to abstract it out and move it into appropriate utility modules. Obviously, there is a trade-off between accessibility and conciseness, in particular since accessibility implies namedness. And accessibility of more-or-less-hidden material implies structured names: We do have module-qualified names --- do we want function-qualified names like f#g in my pseudo-proposal above? Do we want instance-qualified names to get at Show%List%showsPrec or something like that? Do we want mechanisms to hide some of these again, as modules currently do? To some extent it boils down more to style than to substance: accessible functions have to be made accessible in a concsious way, no matter which structured access mechanisms we offer. I don't think that accessibility for the sake of debugging should influence language design decisions more than accessibility for the sake of re-use. Wolfram
participants (2)
-
John Hughes
-
kahl@cas.mcmaster.ca