public/private module sections (was Re[2]: Export lists in modules)

2006-02-23 Thread Claus Reinke

modules M exports

class Eq a where
  (==) :: a - a - Bool

data T :: * - *
f :: T - Int
mkT :: Int - T

where -- implementation below here
--


SM The main difference is that I'm doing away with parentheses, commas, and
SM export specifiers, and using layout and full declaration syntax instead.
SM (I don't really want to discuss this very rough idea any more though,
SM it's just a distraction, and I'm not sure I like it anyway).


let's have a closer look before we dump this again, shall we?-)

if you'd go one step further, you'd replace the public/private modifiers
with public/private module sections. I don't like the modifiers, and I'm 
uncertain about the intermediate form you suggested, but I might be 
able to live with two-section modules:


nothing is duplicated, the public and private items are clearly grouped.
if you like to make the public section look more like an interface, you 
only use short definitions in it (could this be made to work for data type

constructors/class members?).

another neat consequence not available with the other alternatives:
instances could be private (without having to be named), instead of 
flooding into importing modules. 

proper interfaces would still be nice (and useful!), but the general 
opinion seems to be that they're beyond Haskell' (what isn't, really?-).


about tools:
tools can relieve some of pressure on the language design (which is why
I'm more in the camp a language definition should not ignore tools now!-).

but the wrong language design can make the tools' job awkward, so it 
may be useful to look at what a tool can/cannot do:


1 ides may let you browse interfaces, but they don't give a standard form
   of printing those interfaces with the modules they belong to, nor even
   a standard form of those interfaces..

2 ides let you see different locations in your sources in a single window
   (I use this whenever I need to modify the imports while editing in the
   middle of my module; I sometimes use this to see the definition of the
   data types I'm working on). that means that the link between definitions
   and import lists can be implicit, and browsing may bypass import lists/
   export interfaces entirely. that holds for both browsing and navigation.

3 ides can add/remove items from the imports remotely (HaRe does 
   this). they can also generate explicit export/import lists (even my old 
   Hugs.vim supported that), and add types in comments, but if they do 
   so, it is not clear what to do with comments already present (update 
   any types in them? what if they were meant to document alternative/
   old/comming versions..; leave any unidentified comments alone? then 
   we'll duplicate type comments as soon as someone adds any text to

   the automatically generated non-interface..)

4 ides can use tooltips to tell you whether the stuff you're looking at
   is exported or not, but again, that won't usually make it into printouts.

look at the problem from this perspective, and you see that

- haskell98 fails 1/4, profits from (and really needs) 2, doesn't support 
   3 all that well
- public/private modifiers only help with 4, part of their job is covered 
   by 3 already
- public/private sections solve 1/4, may still use 2/3 


so, public/private sections seem to support all pragmatic issues, and
since they're still just haskell code, don't suffer from duplication/scoping/..
issues, either. in fact, we might end up simplifying the syntax be removing
export lists! but exposing only some data constructors of a data type 
would be awkward?


cheers,
claus

___
Haskell-prime mailing list
Haskell-prime@haskell.org
http://haskell.org/mailman/listinfo/haskell-prime


Re: public/private module sections (was Re[2]: Export lists in modules)

2006-02-23 Thread Claus Reinke
let's go through 5.2 Export Lists to see what would be missing 
if we tried to replace the export list with a separation of a module

into a public (exported) and a private (local) part:

---
   module M 
   exports

   body
   where
   body
--

1. value, field name, or class method, whether declared in the 
   module body or imported, may be named by giving the name 
   of the value as a qvarid


   the easiest way to do that is to put the definition of that name
   or a synonym for it in the export section. to reexport names
   from other modules, import those names in the export section.
   
   that approach gets awkward if we only want to export some 
   field names of a data type.

   [ISSUE 1]

2. algebraic datatype T declared by a data or newtype declaration 
   - The form T names the type but not the constructors or 
   field names. 
   
 declare T itself in the local section, declare a type synonym 
   for T in the export section


   - The form T(c1,...,cn), names the type and some or all of its
   constructors and field names. 

   declare T in the local section, and synonyms for T and for 
   some of its fields/constructors in the export section. 


   again, the latter is awkward. worse, it doesn't work when
   constructors are used in patterns. 
   [ISSUE 2]


   - The abbreviated form T(..) names the type and all its 
   constructors and field names 


   declare T in the export section

3. A type synonym T declared by a type declaration 


   declare T in the export section

4. A class C with operations f1,...,fn declared in a class declaration
   - The form C names the class but not the class methods. 


   declare C in the local section. declare a synonym for C in
   the export section. 

   (it is strange that Haskell 98 allows us to export a class 
   without its methods, yet without restricting its use; 
   instantiating such a class would only make sense if all 
   hidden methods had default definitions, wouldn't it?

   so perhaps the class synonym would only need to be
   one-sided: for use, not for adding instances?).

   - The form C(f1,...,fn), names the class and some or all of its methods. 

   declare C in the local section, declare a partial synonym for 
   C, including some of its methods, in the export section. 

   (again, it doesn't seem to make much sense to make that 
   more than a one-sided synonym; see previous point).


   - The abbreviated form C(..) names the class and all its methods

   declare C in the export section

5. The form module M names the set of all entities that are in scope 
   with both an unqualified name e and a qualified name M.e. 


   for re-exports M, import M in the export section.
   for the current module: ??
   the current module seems to need syntax at first, until we realize that 
   this case is already handled by the split into export/local section.


   for imports we don't want to re-export, import them in the local 
   section (so imports need to be allowed in two places, at the 
   beginning of the exported section and at the beginning of the 
   local section (but that seems to be no problem, more relaxed 
   versions of import have been suggested here).


   note that it is no longer possible to export a module M that
   has not been imported. so the description of that error in the 
   report can be removed


--- 
so far, so good, if we can resolve the issues mentioned above,
there is a lot of simplicifation in return: 


   - no export lists
   (so the language definition becomes simpler, and if some 
   future standard tackles module interfaces, they won't have 
   to compete with overlaps between export lists and interfaces)


   - no need to duplicate features of import lists in export lists, 
   as import lists in export sections serve the same purpose 


   - less potential for errors

but that's not the end of the advantages: compared to other
proposals on the table, there is no duplication of type signatures,
nor of export information, and whether or not an item is
exported is directly visible from its presence in either section.
moreover:

6. (cf. 5.4 importing and exporting instances)

   to export an instance, declare it in the export section.
   to avoid exporting an instance, declare it in the local section.
   to import instances for re-export, import them in the export
   section.
   to import instances *without re-exporting* them, import
   them in the local section! (hooray!-)

   this is not a perfect success, however: we have selective
   export of instances, but not selective import - we have no 
   chance to import names from a module M without importing 
   its exported instances as well.

   [ISSUE 3]

the more I think about it, the more I like it (which probably
means that there is some ugly part of it that I'm not thinking
about;-). the outstanding