Problem with hierarchical libraries in Hugs compared to ghc/nhc98
When trying to make our Haskell tracer Hat work with Hugs (November 2002) I noticed that * Hugs' implementation of hierarchical libraries differs from those of ghc and nhc98, and * Hugs' implementation choice makes it more restrictive than ghc/nhc98 A simple example: There is module B in file B.hs There is module Test.B in file Test/B.hs There is module Test.A in file Test/A.hs Module Test.A contains "import B". When compiling module Test.A both nhc98 and ghc imports module B from file B.hs. In contrast, Hugs imports module Test.B from file Test/B.hs and then stops with an error, because the module name is wrong. The simple reason why Hugs behaves so is that when searching a module it *always* searches the current directory (* where the import was demanded *) first. Only afterwards the paths set with the -P option are searched. I know that we generally try to avoid specifying filename and directory issues. However, this is not really a filename issue, but a problem of relative and absolute module names (wrt possibly several hierarchies). An "import B" in module Test.A could mean either module B or module Test.B. I suggest that the absolute module name takes precedence, because otherwise there is no way to import module B from module Test.A, whereas you can always import module Test.B from module Test.A by saying "import Test.B". I admit that this has the slight disadvantage that moving a set of modules into the hierarchical library will require not only changing all module names at the top but also in every import declaration, to not inadvertedly import the wrong module. So in the end this suggests that we should not allow relative module names at all. Note that this proposal still allows the current directory (of Hugs or in which the compiler was started) to be the root of the hierarchy that is searched first. In fact, this is probably the desirable default behaviour. Currently the hierarchical library proposal http://www.haskell.org/~simonmar/libraries/libraries.html does not say much about the semantics of the hierarchical module names. It really should. I'd very much like to hear other people's opinion on this (especially the Hugs maintainers'). The current behaviour of Hugs makes it impossible for Hat to work with Hugs. Hat creates a shadow hierarchy of transformed libraries: the transformed variant of Prelude is Hat.Prelude, the transformed variant of Control.Arrow is Hat.Control.Arrow etc. Nearly all of the transformed modules import both Prelude and Hat.Prelude ... Olaf -- OLAF CHITIL, Dept. of Computer Science, The University of York, York YO10 5DD, UK. URL: http://www.cs.york.ac.uk/~olaf/ Tel: +44 1904 434756; Fax: +44 1904 432767
On Fri, Mar 07, 2003 at 02:35:47PM +0000, Olaf Chitil wrote:
When trying to make our Haskell tracer Hat work with Hugs (November 2002) I noticed that
* Hugs' implementation of hierarchical libraries differs from those of ghc and nhc98, and * Hugs' implementation choice makes it more restrictive than ghc/nhc98
A simple example: There is module B in file B.hs There is module Test.B in file Test/B.hs There is module Test.A in file Test/A.hs Module Test.A contains "import B".
When compiling module Test.A both nhc98 and ghc imports module B from file B.hs. In contrast, Hugs imports module Test.B from file Test/B.hs and then stops with an error, because the module name is wrong.
The simple reason why Hugs behaves so is that when searching a module it *always* searches the current directory (* where the import was demanded *) first. Only afterwards the paths set with the -P option are searched.
[noble attempt at rationalizing Hugs's behaviour omitted]
This is a clear flaw in Hugs (long known, but hard to fix). A workaround is to add the -X option to stop it adding the extra directory.
Ross Paterson wrote:
On Fri, Mar 07, 2003 at 02:35:47PM +0000, Olaf Chitil wrote:
The simple reason why Hugs behaves so is that when searching a module it *always* searches the current directory (* where the import was demanded *) first. Only afterwards the paths set with the -P option are searched.
This is a clear flaw in Hugs (long known, but hard to fix). A workaround is to add the -X option to stop it adding the extra directory.
Thank you very much for pointing me to the -X option which I had not noticed before. Why is it hard to fix if -X actually exists? Why not have -X as default? Is the current default behaviour good for anything? I still suggest putting some semantical description into the hierarchical libraries extension document, so that people like me do not jump to wrong conclusions because of the similarity with directory structures. Olaf -- OLAF CHITIL, Dept. of Computer Science, The University of York, York YO10 5DD, UK. URL: http://www.cs.york.ac.uk/~olaf/ Tel: +44 1904 434756; Fax: +44 1904 432767
On Fri, Mar 07, 2003 at 05:44:27PM +0000, Olaf Chitil wrote:
Ross Paterson wrote:
On Fri, Mar 07, 2003 at 02:35:47PM +0000, Olaf Chitil wrote:
The simple reason why Hugs behaves so is that when searching a module it *always* searches the current directory (* where the import was demanded *) first. Only afterwards the paths set with the -P option are searched.
This is a clear flaw in Hugs (long known, but hard to fix). A workaround is to add the -X option to stop it adding the extra directory.
Thank you very much for pointing me to the -X option which I had not noticed before.
Why is it hard to fix if -X actually exists? Why not have -X as default? Is the current default behaviour good for anything?
Suppose you load a file with some long name. You'd like that module to be able to import other modules in (or relative to) the same directory. This is important for runhugs, but also for the normal interpreter. (Only works if the original module has a non-heirarchical name, of course.) In my opinion the correct fix is to add the directory only if the parent module was specified with a path, or was itself found relative to that added directory.
Ross Paterson wrote:
Why is it hard to fix if -X actually exists? Why not have -X as default? Is the current default behaviour good for anything?
Suppose you load a file with some long name. You'd like that module to be able to import other modules in (or relative to) the same directory. This is important for runhugs, but also for the normal interpreter. (Only works if the original module has a non-heirarchical name, of course.)
Yes, this makes sense.
In my opinion the correct fix is to add the directory only if the parent module was specified with a path, or was itself found relative to that added directory.
I agree. So a search directory is only passed on recursively, if the imported module is actually found in that directory. So there is at most one added path. However, because Hugs has this extension of allowing paths in import declarations, the path may be different for every module. I suppose one problem with fixing Hugs' behaviour is that it currently does not distinguish modules with path and hierarchical names, that is, e.g. Test/A and Test.A I have to admit that I think that all this becomes rather complicated and I wonder if it would not be better to just require the user to set the search path with -P and not use any explicit paths in module names. -- OLAF CHITIL, Dept. of Computer Science, The University of York, York YO10 5DD, UK. URL: http://www.cs.york.ac.uk/~olaf/ Tel: +44 1904 434756; Fax: +44 1904 432767
On Mon, Mar 10, 2003 at 07:53:57PM +0000, Olaf Chitil wrote:
Ross Paterson wrote:
In my opinion the correct fix is to add the directory only if the parent module was specified with a path, or was itself found relative to that added directory.
I agree. So a search directory is only passed on recursively, if the imported module is actually found in that directory.
I've had a look, and it's not so hard to do what I suggested, but the changes would be cleaner if the search strategy for module names, currently [ d++f++e | f <- files, d <- dirs, e <- hugsSuffixes ] where dirs = addAlong ("" : hugsPath) files = [mod2dir nm, nm] addAlong | wantImplicitRoot = (along:) | otherwise = id mod2dir s = map (\c -> if c=='.' then slash else c) s were also changed to [ d++f++e | d <- dirs, f <- files, e <- hugsSuffixes ] i.e. swap the first two generators. I think that having the generator order match the concatenation order is more comprehensible; it's also closer to what GHC does (except GHC has files = [nm, mod2dir nm]). It does sometimes mean checking a few more files before finding a match, but not always adding the extra directory will also save some checks. Any views?
Ross Paterson wrote:
I've had a look, and it's not so hard to do what I suggested, but the changes would be cleaner if the search strategy for module names, currently [...] i.e. swap the first two generators. [...] Any views?
Looks fine to me. Note that in my opinion the extra directory should only be added, if the import or load really contained a path with slashes, not if it is a pure hierarchical module name. I suppose it is sensible for Hugs to accept names such as A/B/C.D.E but it currently also accepts names such as A.B.C/D/E, which I think it should not. Olaf -- OLAF CHITIL, Dept. of Computer Science, The University of York, York YO10 5DD, UK. URL: http://www.cs.york.ac.uk/~olaf/ Tel: +44 1904 434756; Fax: +44 1904 432767
Ross Paterson
the changes would be cleaner if the search strategy for module names, currently
[ d++f++e | f <- files, d <- dirs, e <- hugsSuffixes ] where files = [mod2dir nm, nm]
were also changed to
[ d++f++e | d <- dirs, f <- files, e <- hugsSuffixes ]
i.e. swap the first two generators.
Better yet, drop the support for interpreting the '.' as anything but a hierarchial module namespace separator. That is, use this:
[ d ++ mod2dir nm ++ e | d <- dirs, e <- hugsSuffixes ]
The last release rightly supported both old and new style names. We're already committed to dropping the non-hierarchial libraries in future releases. Let's drop non-hierarchial names too. [I also lean towards dropping the implicit search of the current directory too but I'm not certain enough of the consequences of such a change.] -- Alastair Reid alastair@reid-consulting-uk.ltd.uk Reid Consulting (UK) Limited http://www.reid-consulting-uk.ltd.uk/alastair/
participants (3)
-
Alastair Reid -
Olaf Chitil -
Ross Paterson