Cabal projects

Contents
cabal init
The .cabal file
Build and run
Project layout

cabal init

A real project starts with a directory and one command. Cabal asks a few questions and writes the skeleton:

mkdir todo && cd todo && cabal init

Package name? [default: todo] Package version? [default: 0.1.0.0] What does the package build: 1) executable ... Guessing dependencies...

Answer 1 for an executable, accept the defaults, and choose base as the only dependency for now.

The .cabal file

The generated todo.cabal is the project description. Four stanzas matter at this stage:

cabal-version: 3.0 name: todo version: 0.1.0.0 executable todo main-is: Main.hs hs-source-dirs: app build-depends: base >=4.18 && <5 default-language: Haskell2010

build-depends is the dependency list, and the version bounds are a promise about which versions your code was tested against. Keep them loose but present.

Build and run

Four commands cover the whole edit cycle. Cabal caches what it built, so the second run is fast:

cabal build

cabal run todo

cabal repl

ghci> :t main main :: IO ()

cabal repl loads the project modules with the right paths and dependencies, which is why it beats a bare ghci once the project has more than one file.

Project layout

The conventional layout separates the program from the library so that tests can import the logic without running main:

todo/ ├── app/Main.hs ├── src/Todo.hs ├── test/Spec.hs ├── todo.cabal └── cabal.project

The executable depends on the library and does nothing but parse arguments and call it. That single decision is what makes the capstone testable in lesson 49.

Next: Dependencies

Article author: Arthur Isaev

Related articles
Haskell
Haskell course: zero to hero in 50 lessons
What is Haskell and why it matters
Install the toolchain with GHCup
GHCi: the interactive shell
Your first program
Values with let and where
Types and type signatures
Functions and application
Currying and partial application
Operators, sections, and fixity
if, guards, and pattern guards
case expressions
Pattern matching
Tuples
Lists
Ranges and enumeration
List comprehensions
Recursion replaces loops
map, filter, and foldr
Lambdas and composition
Type classes
Parametric polymorphism
Maybe and null safety
Either and recoverable errors
data: product types
data: sum types
Records
newtype and type synonyms
Recursive data: binary trees
Functor
Applicative
Monad
do notation
IO and purity
Files and IO
Modules and imports
Cabal projects
Dependencies
Testing with HUnit
Property testing with QuickCheck
Laziness and infinite lists
Strictness and space leaks
Folds
Monoids
Traversable
Monad transformers
Errors and exceptions
Concurrency
Parsing with Megaparsec
Capstone: a todo CLI
Hero roadmap: the whole course on one page

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: