This is the second part of a hands-on guide on creating a Haskell based web service. No previous knowledge of haskell is required. However, basic understanding of RESTful web services is assumed. Other posts in this series: part 1, part 3.
2. Build and package a simple app using cabal
Cabal (Common Architecture for Building Applications and Libraries) is a system for building and packaging Haskell libraries and programs. Think of it as Haskell’s equivalent of Python’s
npm and Scala’s
Before we get started, make sure that you have
cabal installed and on the system path:
% cabal — version cabal-install version 220.127.116.11 using version 18.104.22.168 of the Cabal library
Create a cabal app
Cabal makes it easy to build, package and test your application. It’s also straightforward to add dependencies on other libraries that cabal will fetch for you.
It is possible that different Haskell apps have dependencies on different versions of the same library. To prevent conflicts in your global Haskell environment, it’s a good idea to create a sandbox for your app. Cabal will then install the dependent libraries inside the sandbox.
% mkdir cabal-example % cd cabal-example % cabal sandbox init Writing a default package environment file to /Users/psingh/tmp/haskell/eac-articles/cabal example/cabal.sandbox.config Creating a new sandbox at /Users/psingh/tmp/haskell/eac-articles/cabal-example/.cabal-sandbox
Now, we can initialise our app. The easiest way to create a cabal app is using the
cabal init command. Follow the prompts and cabal will generate the config file for you. Here’s an example interaction on my system:
% cabal init Package name? [default: cabal-example] Package version? [default: 0.1.0.0] Please choose a license: * 1) (none) 2) GPL-2 3) GPL-3 4) LGPL-2.1 5) LGPL-3 6) AGPL-3 7) BSD2 8) BSD3 9) MIT 10) ISC 11) MPL-2.0 12) Apache-2.0 13) PublicDomain 14) AllRightsReserved 15) Other (specify) Your choice? [default: (none)] 9 Author name? [default: Parambir Singh] Maintainer email? [default: email@example.com] Project homepage URL? Project synopsis? Project category: * 1) (none) 2) Codec 3) Concurrency 4) Control 5) Data 6) Database 7) Development 8) Distribution 9) Game 10) Graphics 11) Language 12) Math 13) Network 14) Sound 15) System 16) Testing 17) Text 18) Web 19) Other (specify) Your choice? [default: (none)] What does the package build: 1) Library 2) Executable Your choice? 2 What is the main module of the executable: * 1) Main.hs (does not yet exist) 2) Main.lhs (does not yet exist) 3) Other (specify) Your choice? [default: Main.hs (does not yet exist)] 1 What base language is the package written in: * 1) Haskell2010 2) Haskell98 3) Other (specify) Your choice? [default: Haskell2010] 1 Include documentation on what each field means (y/n)? [default: n] n Source directory: * 1) (none) 2) src 3) Other (specify) Your choice? [default: (none)] 1 Guessing dependencies… Generating LICENSE… Generating Setup.hs… Generating cabal-example.cabal… Warning: no synopsis given. You should edit the .cabal file and add one. You may want to edit the .cabal file and add a Description field.
You will now have a
cabal-example.cabal file in your source directory. Remember that we selected
Main.hs as our main module during the
cabal init process. Add a
Main.hs file now to the root of your source folder with the following content:
c2f c = (c * 9/5) + 32 main = do print (c2f 37)
Running your cabal app (cabal run)
To run your app, use the
cabal run command:
% cabal run Package has never been configured. Configuring with default flags. If this fails, please run configure manually. Resolving dependencies… Configuring cabal-example-0.1.0.0… Preprocessing executable ‘cabal-example’ for cabal-example-0.1.0.0… [1 of 1] Compiling Main ( Main.hs, dist/build/cabal-example/cabal-example-tmp/Main.o ) Linking dist/build/cabal-example/cabal-example … Running cabal-example… 98.6
Other useful cabal commands
Removes the generated artifacts (executables etc.)
% cabal clean cleaning… cabal build Compiles and links your source code to generate the executable. % cabal build Package has never been configured. Configuring with default flags. If this fails, please run configure manually. Resolving dependencies… Configuring cabal-example-0.1.0.0… Building cabal-example-0.1.0.0… Preprocessing executable ‘cabal-example’ for cabal-example-0.1.0.0… [1 of 1] Compiling Main ( Main.hs, dist/build/cabal-example/cabal-example-tmp/Main.o ) Linking dist/build/cabal-example/cabal-example … Run the generated executable: % ./dist/build/cabal-example/cabal-example 98.6
Installs the generated artifact into the cabal sandbox. This is somewhat similar to
mvn install in Java world.
% cabal install Resolving dependencies… Notice: installing into a sandbox located at /Users/psingh/tmp/haskell/eac-articles/cabal-example/.cabal-sandbox Configuring cabal-example-0.1.0.0… Building cabal-example-0.1.0.0… Installed cabal-example-0.1.0.0
ghci session for your project (i.e. with your modules loaded). You can easily test your functions here.
% cabal repl Preprocessing executable ‘cabal-example’ for cabal-example-0.1.0.0… GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help [1 of 1] Compiling Main ( Main.hs, interpreted ) Ok, modules loaded: Main. *Main> c2f 37 — call the c2f function defined in our Main.hs file 98.6 *Main> main — yes, this is the main function we defined in Main.hs 98.6 *Main>
Downloads the latest package list for cabal. It’s useful to run
cabal update before running
cabal init or
cabal install to make sure that cabal has knowledge about the latest packages
% cabal update Downloading the latest package list from hackage.haskell.org
The complete source for this section is available on github
In Part 3, We’ll write a simple web app using the Scotty web framework for Haskell.