10
votes

I am writing a (actually my first) largish program in Haskell and am trying to break up my program into modules, so that it might be easier to maintain. In Haskell, the module names seem to be dependent upon the directory structure. This is perfectly fine till I have to embed another layer of directory structure for the program. Ill give a very simple example below:

Let us say that we are starting out with a Haskell program with the following directory structure.

  • Names in [square brackets] represent directories,
  • names in {curly braces} represent modules,
  • names in (normal brackets) represent file names associated within the modules
[src]
    - (Main.hs) {Main}
    - (PRBS.hs) {PRBS}
    - [Hardware]
        - (DataDef.hs) {Hardware.DataDef}
        - (ShiftRegister.hs) {Hardware.ShiftRegister}

This is all fine. I can import everything I want wherever I want it. However, now say I want to create another level of abstraction, like so:

[src]
    - (Main.hs) {Main}
    - [Firmware]
        - (PRBS.hs) {Firmware.PRBS}
        - [Hardware]
            - (DataDef.hs) {Firmware.Hardware.DataDef}
            - (ShiftRegister.hs) {Firmware.Hardware.ShiftRegister}

Notice now that the names of all modules in Hardware have changed. I now have to change the module names within each file, and in all the other files where the files are imported. The three files I have shown in just an example. If the directory structure ends up having hundreds of files with tens of embedded directories, then it might become impossible to maintain code. Furthermore, if at any point, I want to copy a directory (and its subdirectories at a particular point in the current directory system), I need to figure out all the previous directories that come before it, and manually change the module names within each file.

Since Haskell is used in several large projects, I am very certain that I am missing something here. Any help in getting me out of this quagmire will be greatly appreciated!

1
I don't know of a tool or approach that works around this, but it sounds like it would be a fun little program to write for updating the module names recursively when you change structure like that.bheklilr
Ha ha, I think your definition of little just caused a disturbance in the Force.ssm
For specificity: this is how it is in GHC, but not Haskell as a whole. The spec actually doesn't say at all how the compiler should find modules. I suspect that a well-done patch that expands GHC's search abilities would be accepted... but be sure to solicit comments before you start hacking, as this is definitely something that has been discussed before and there's lots to be mindful of in a good design.Daniel Wagner
@ssm It isn't very good yet, but it's something I threw together because I was bored. You could pretty easily build off of it into a nice little tool that handles more scenarios, like literate haskell, pragmas at the top, etc. I just wanted to get a proof of concept and did so in about 100 lines. Not too bad, but would need significantly more work to add error handling and more support for common use cases.bheklilr
Couldn't you just put Firmware in GHC's import search path? (Using hs-source-dirs from cabal or -isrc/Firmware for GHC)bennofs

1 Answers

1
votes

If you have perl and bash and find and all that, you can do something like this:

find Firmware/Hardware/ -name '*.hs' -exec perl -i.bak -pe \
       's/^module (Hardware\.\S+)/module Firmware.$1/' \
       {} \;
diff Firmware/Hardware/DataRef.hs{,.bak}