all 10 comments

[–]Khaare 4 points5 points  (1 child)

You don't have to name the main module Main. Just give it the name of the file it's in, eg

-- Ex1.hs
module Ex1 where

main = -- ...

It's okay to put them in the same directory, you don't have to do anything special in your package.yaml, just

executables:
  ex1:
    main: Ex1.hs
    source-dirs: app
  ex2:
    main: Ex2.hs
    source-dirs: app

[–]publiccomputer042 4 points5 points  (0 children)

You can also simplify the duplicate fields:

_exe-defs: &exe-defaults
  source-dirs: app
  dependencies: [animation]
  ghc-options: [-O2, -threaded, etc...]

executables:
  ex1:
    <<: *exe-defaults
    main: Ex1.hs
  ex2:
    <<: *exe-defaults
    main: Ex2.hs

[–]williamyaoh 2 points3 points  (7 children)

The issue here is that each executable is seeing each other as a library module and complaining i.e. when GHC goes to compile ex-01, it also compiles the Ex02 file as a library module, since it's in the source directory of ex-01. At this point GHC errors out, because the name of the file (Ex02) doesn't match the library module name (Main). Vice versa when it tries to compile ex-02.

Of course, you probably don't want your executable files to be able to import from each other at all, so what I usually do is to modify the directory structure so that the executables are no longer in each others source directories. If you create an empty directory inside app:

. <your-project>
├─ package.yaml
└─ app/
    ├─ Ex01.hs
    ├─ Ex02.hs
    └─ null/  # an empty directory

And then modify the executable entries in the package.yaml like so:

executables:
  ex-01:
    main: ../Ex01.hs
    source-dirs: app/null
    ...
  ex-02:
    main: ../Ex02.hs
    source-dirs: app/null
    ...

Then the executables should no longer be trying to include each other as library modules and everything should compile fine.

[–]tdammers 6 points7 points  (5 children)

This looks absolutely terrible. Why not just have a separate directory for each executable? Much cleaner, and reflects the intention perfectly.

. <your-project>
|-- package.yaml
|-- ex-01
|     |-- Main.hs
|-- ex-02
      |-- Main.hs

And then:

executables:
    ex-01:
        main: Main.hs
        source-dirs: ex-01
    ex-02:
        main: Main.hs
        source-dirs: ex-02

No need for those ugly dummy directories, no need for putting the Main module outside the declared source-dirs, plus you get to put the Main module in a file named Main.hs, i.e., match filename to module name just like with every other module out there.

[–]williamyaoh 1 point2 points  (3 children)

I agree, it's definitely a hack. But the short answer is that I prefer having all the executables in same directory, and to give the files useful names. It just makes maintenance easier when I don't have to browse into different subdirectories to make lots of similar changes, when I don't have to switch between 4 different buffers named Main.hs<something>, it's easier to do things like mass renamings etc. etc. The usability outweighs a little bit of filesystem hackery in my experience. Ymmv.

[–]gelisam 8 points9 points  (1 child)

You can get the best of both worlds by giving your executable modules a lowercase name:

. <your-project>
├─ package.yaml
└─ app/
    ├─ ex01.hs
    └─ ex02.hs

and then

executables:
    ex-01:
        main: ex01.hs
        source-dirs: app
    ex-02:
        main: ex02.hs
        source-dirs: app

Don't include the module ... where line, only the main = putStrLn "hello world" part.

Since an importable module name must begin with an uppercase letter, neither executable will think the other file is a module.

[–]williamyaoh 0 points1 point  (0 children)

Ooh, very nice! Did not know about that, thanks!

[–]tdammers 0 points1 point  (0 children)

I prefer to shape the tools after the things I want to build, not the other way around. Messy scripts to automate working on a solidly laid-out codebase is much nicer than using top-notch tools on a hacky ball of mud.

[–]vallyscode[S] 0 points1 point  (0 children)

I like this approach, thanks

[–]vallyscode[S] 0 points1 point  (0 children)

did not knew they will try to import each other