[Haskell-cafe] mutually recursive modules

Alastair Reid alastair at reid-consulting-uk.ltd.uk
Fri Sep 24 09:43:57 EDT 2004

The original Haskell design included interface files usually with names like 

IIRC, Yale Haskell expected them to be hand-written while HBC and GHC 
machine-generated but allowed the careful user to write them by hand.
Sometime around Haskell 1.4 or 98, they were dropped because Yale Haskell had 
died and there seemed little point in specifying the format of 
machine-generated files.

(Hugs' support for modules was added long after the original Hugs design - it 
was hard getting it to do as much as it does.  At one point, I almost had it 
supporting mutually recursive modules but I couldn't quite get all the 
dependencies in the typechecker under control so I settled for just 
supporting module namespaces and qualifiers.)

It is _almost_ possible to generate .hiboot files automatically.  If you see a 
data declaration in the .hs file, copy it to the .hiboot file, if you see a 
function prototype, copy it, etc.  That is, you generate a .hiboot file by 
just deleting all function definitions.

One of the tedious bits is that that you need to do a tricky least fixpoint 
calculation just to figure out what is exported by a set of mutually 
recursive modules if they each reexport their imports.  

Generating .hiboot files by just deleting function definitions fails if there 
is no prototype for an exported function.  A crude approach is to assume the 
type (\forall a. a) for any function with no prototype but, although this is 
sound (I think), it will cause valid programs to be rejected.  This problem 
could be overcome by specifying it as the correct behaviour :-) (Is it sound 
to use (\forall a. a) in the presence of higher-kinded types and all those 
other extensions?)

Hmmm, maybe someone familiar with the Haskell-source libraries could quickly 
hack up a program to generate .hiboot files automatically and make it 
available - that would quickly find the issues (and also identify any 
weaknesses in ghc's error checking of .hiboot files :-).

Alastair Reid

>  It's interesting how other languages [handle mutually recursive modules]
>  problem. In Modula-3 it is solved by explicit module interfaces and
>  partial revelation. One can 
> define type T in module A and type T in module B very abstractly as
> pointers to something and the complete data structures (which may contain
> references to either interface) are usually revealed in the
> implementations of the modules. I'm curious how Oberon solves it, because
> it doesn't need explicit interfaces but derives them from the
> implementation files. Probably one can say that Oberon extracts something
> like a .hiboot file from every module file automatically. Why can't GHC
> and Hugs go this way?

More information about the Haskell-Cafe mailing list