[Haskell-cafe] mutually recursive modules
fjh007 at galois.com
Mon Sep 27 13:46:25 EDT 2004
On 24-Sep-2004, Jan-Willem Maessen <Janwillem.Maessen at Sun.COM> wrote:
> An anecdotal note -
> hbcc (the front end to the pH and Eager Haskell compilers, and also of
> GRIN) contained several mutually recursive modules both in the compiler
> and in the prelude.
> One of the best things we ever did was get rid of the mutual recursion.
> The resulting refactoring helped us to group related pieces which had
> (for historical reasons) ended up scattered. It also cut our rebuild
> time dramatically, and let us do cross-module inlining and optimization
> In short, using mutual recursion was probably a bad idea, and we found
> we were better off without it.
Here's another anecdotal note.
When refactoring the Cryptol compiler, in particular when abstracting
some interfaces to use type classes, I found that
(1) In the intermediate stages of the refactoring, I needed to
use mutual recursion in quite a few different places.
This was a pain because it required manually writing .hi-boot
files. This was also problematic because my colleagues were
reluctant to have our sources depend on a rather poorly
supported feature of Haskell, and were also reluctant to
have implementation-specific files like .hi-boot files in
our CVS repository. As a result, I did not check in the
intermediate stages of the refactoring into our CVS repository.
These factors made the development process more difficult,
made the code review process more difficult, and increased
the likelihood of a CVS conflict.
(2) Although most of the mutual recursion occurred only in the
intermediate stages of the refactoring, some of the mutual
recursion remained at the end of the refactoring, forcing
two modules with only the smallest degree of coupling to be
combined into a single module.
The two modules in question were (a) the module which defines
the calling interface between the Cryptol front-end and the
various Cryptol back-ends, and (b) the module which defines the
structure which records the settings of command-line options.
Here (a) depends on (b) because one of the parameters which
is passed to the back-ends is the command-line option settings,
and (b) depends on (a) because one of the option settings is
the currently selected back-end (represented using an
existentially quantified typeclass-constrained type).
So while I agree that unrestrained use of mutual recursion can lead to
poor structuring, I think that in many cases mutual recursion _is_ useful,
either as an intermediate stage during refactoring or as a final stage.
A compiler warning about mutual recursion (with some way to suppress it
in individual cases) might be useful, but a compiler error or the
requirement to manually write separate .hi-boot files is not helpful, IMHO.
Fergus J. Henderson | "I have always known that the pursuit
Galois Connections, Inc. | of excellence is a lethal habit"
Phone: +1 503 626 6616 | -- the last words of T. S. Garp.
More information about the Haskell-Cafe