[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
Main.hi
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