My understanding is that the dotted syntax of modules, in Haskell, represents logical structure on disk. So, if we have a structure like this:
Main.hs
Foo/
Bar.hs -- exports "Bar"
Quux.hs -- exports "Quux"
...then in our Main.hs
, we can do:
import Foo.Bar
import Foo.Quux
(I assume we can only have modules at leaf nodes of the filesystem. For example, in the above, there's no way we could have a Foo
module, as well.)
In this example, we're traversing down the tree. What happens if we want to go up?
lib/
SomeModule.hs
XYZ.hs
src/
Main.hs
That is, in Main.hs
, how do we import SomeModule
or XYZ
?
Maybe this wouldn't be a common occurrence with Main
, but what about inter-module dependencies? They could legitimately need to reference "cousin" nodes.
Just use the fully qualified name of the module and tell GHC where to find the root of the module hierarchy with the -i
option. In your example, this means that you should use import XYZ
in Main.hs
to import the module and the command ghc -i../src --make Main.hs
to compile your program. If you need to compile mutually recursive modules, take a look at this section of the GHC manual.
If you're using Cabal to build your package, you can group the modules under lib
in a library and then make that library a dependency of your executable. You will have the following directory structure:
some-package.cabal
lib/
XYZ.hs
src/
Main.hs
The relevant parts of the some-package.cabal
file will look like this:
Name: some-package
Version: 1.0
...
Library
...
Exposed-modules: XYZ
Hs-source-dirs: lib
...
Executable some-executable
...
build-depends: some-package == 1.0
...
...
This is especially useful if your package includes a test or benchmark suite, because the modules under lib
will be compiled only once.
Here's a real-life example of this technique.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With