21

I was following the stack guide and I got a new project setup (yay!).

It generated the following file layout:

.
├── app
│   ├── Main.hs
├── .gitignore
├── LICENSE
├── helloworld.cabal
├── Setup.hs
├── src
│   └── Lib.hs
├── stack.yaml
└── test
    └── Spec.hs

According to the "Files in helloworld" section of the guide:

The app/Main.hs, src/Lib.hs, and test/Spec.hs files are all Haskell source files that compose the actual functionality of our project (we won't dwell on them here).

I really wish they had dwelled on that for a second, because I have no idea what the distinction between app/Main.hs and src/Lib.hs should be. Which code should I put where?

In what ways am I supposed to divide code between app/, src/, app/Main.hs and src/Lib.hs?

If I'm just writing an application or just writing a library, do I need both files/directories?

Sunjay Varma
  • 5,007
  • 6
  • 34
  • 51
  • 2
    If you do not have an executable you can delete main.hs and the respective parts in the cabal file. In the other case i would try to provide as much functionality as a library and only have a minimal io related executable. But if you are new to haskell do as you feel comfortable and don't worry too much. Ultimately i think, this is more a matter of style/taste than a formally answerable question. – epsilonhalbe Aug 21 '16 at 23:49

2 Answers2

13

This separation of modules into folders can be any way you want. The naive idea is that you put almost all logic into the Lib folder. Main.hs then just

  • imports required parts from Lib,
  • reads command-line arguments, and
  • runs stuff.

You can rename app into executables and change the corresponding lines in .cabal file. Actually, you can come up with an arbitrary file hierarchy.

In our company project, we use another but also very popular approach. And our file hierarchy looks like this:

.
|-- bench
|-- src
    |-- exec1
        |-- Main.hs
    |-- exec2
        |-- Main.hs
    |-- SuperCoolLibrary
        |-- LibModule1.hs
        |-- LibModule2.hs
|-- test
|-- Setup.hs

Other stack.yaml, .cabal, etc. files are not shown here.

Actually, if you are writing an application, you can just create one Main.hs file and put all logic inside the main function. You won't believe it but as a Haskell lecturer I saw such code from my students :( Though I don't suggest you write code that way.

If you are writing a library then you don't need Main.hs files and the main function at all. You can look at a simple example like this library (it allows you to automatically generate command-line options from data types): optparse-generic

I hope I helped clearing up your confusion.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Shersh
  • 9,019
  • 3
  • 33
  • 61
  • 1
    Thanks! Some relevant cabal documentation regarding what you said about changing corresponding lines in `.cabal` - https://www.haskell.org/cabal/users-guide/developing-packages.html#editing-the-.cabal-file – Sunjay Varma Aug 22 '16 at 02:54
5

The main reason it's typically set up like this even for an application is for writing tests. Say you create a default stack project called foo, the test suite foo-test will depend on the foo library, as will the foo-exe. If you were to put all your functions into app/Main.hs, then those functions cannot be tested from the foo-test test suite.

If you're just playing around and don't care about having a test suite, you could base your stack project on the simple template:

$ stack new foo simple

If you'd like to set up testing, I like tasty. You'd modify your .cabal file something like this:

test-suite foo-test
  type:                exitcode-stdio-1.0
  hs-source-dirs:      test
  main-is:             Spec.hs
  build-depends:       base
                     , foo
                     , tasty
                     , tasty-hunit
                     , tasty-quickcheck
  ghc-options:         -threaded -rtsopts -with-rtsopts=-N
  default-language:    Haskell2010

Then take a look at the example.

Steven Shaw
  • 6,063
  • 3
  • 33
  • 44