Access to hidden entities, was: Re: Export lists in modules

kahl at cas.mcmaster.ca kahl at cas.mcmaster.ca
Thu Feb 23 10:03:14 EST 2006


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






More information about the Haskell-prime mailing list