Setting up a Haskell Development Environment
Table of Contents
- 1. Haskell
- 1.1. Overview
- 1.2. Setting up a Haskell Development Environment
- 1.3. Haskell stack tool
- 1.3.1. Using stack without a project
- 1.3.1.1. Overview
- 1.3.1.2. Installing packages globally
- 1.3.1.3. Running Haskell REPL without a project
- 1.3.1.4. Run a specific GHC version
- 1.3.1.5. Run a Haskell script with specific ghc version:
- 1.3.1.6. Compile a haskell source code without a project
- 1.3.1.7. Compile a sources without a project with a specific Haskell version
- 1.3.1.8. Misc
- 1.3.2. Build and manage projects with Stack
- 1.3.3. Exploring Stack
- 1.3.4. Some useful packages
- 1.3.1. Using stack without a project
- 1.4. GHCI Reference
1 Haskell
1.1 Overview
Features
- Pure Functional programming language
- Strong Static Typed Language
- Type Inference (The Haskell compiler deduces the types for you).
- Lazy Evaluation (Delayed evaluation) by default
- Data Immutability / Haskell has no variables
- Values can be bound to a name and can only be assigned once.
- Values can never change.
- Haskell has not for-loop, while statements.
- Algebraic Data types
- Pattern Matching
- Tail Recursions
- Compiles to native code.
Tool
ghc - the Glasgow Haskell Compiler | Transforms Haskell Source code .hs into native code. |
ghci | Haskell Interactive Shell / Interpreter |
runghc | Haskell Non Interactive Interpreter |
haddock | Documentation tool for annotated Haskell source code |
cabal | GHC Haskell Cabal building tool |
stack | Haskell new package manager and building automation tool. |
Suffixes of file names for Haskell
Extension | Description | |
---|---|---|
Source File | ||
.hs | Haskell source code; preprocess, compile | |
.lhs | literate Haskell source; unlit, preprocess, compile | |
Compilation output | ||
.hi | Interface file; contains information about exported symbols | |
.hc | intermediate C files | |
.x_o | way x object files; common ways are: p, u, s | |
.x_hi | way x interface files | |
1.2 Setting up a Haskell Development Environment
1.2.1 Gettin Haskell through stack
There are many ways to install Haskell like through Haskell Platform and Linux distributions packages. The most easier and reliable way is through stack tool which is a package manager and a build automation tool for Haskell because it can install and run multiple Haskell GHC versions without breaking each other or overwritten the already installed ghc in the system.
Capabilities:
- Install and run multiple versions of GHC avoiding the dependency hell and that each GHC version overwrites or breaks each other. All ghc versions are installed in the ~/.stack directory.
- Can resolve and install all dependencies per project automatically.
- Simple configuration file in YAML format stack.yaml.
- Reliability: Fetch packages from a curated set of packages
- Reproducible builds.
- Ensures backward compatibility.
Install stack
See the instructions to install stack at https://www.haskellstack.org/
Documentation
1.2.2 Text editor
1.2.2.1 Atom
1.3 Haskell stack tool
1.3.1 Using stack without a project
1.3.1.1 Overview
Stack can be used exploratory programming without setting up a project by running any stack command outside a project directory (a directory without an stack.yaml file).
LST Version / Resolver | Haskell Version |
---|---|
lts-8.3 | GHC 8.0.2 |
lts-7.19 | GHC 8.0.1 |
lts-6.30 | GHC 7.10.3 |
lts-3.22 | GHC 7.10.2 |
lts-2.22 | GHC 7.8.4 |
lts-0.7 | GHC 7.8.3 |
1.3.1.2 Installing packages globally
To install a package globally run $ stack install <package>
outside
any project directory.
$ cd ~ $ stack install HUnit [1 of 2] Compiling Main ( /home/arch/.stack/setup-exe-src/setup-mPHDZzAJ.hs, /home/arch/.stack/setup-exe-src/setup-mPHDZzAJ.o ) [2 of 2] Compiling StackSetupShim ( /home/arch/.stack/setup-exe-src/setup-shim-mPHDZzAJ.hs, /home/arch/.stack/setup-exe-src/setup-shim-mPHDZzAJ.o ) Linking /home/arch/.stack/setup-exe-cache/x86_64-linux/tmp-Cabal-simple_mPHDZzAJ_1.24.0.0_ghc-8.0.1 ... HUnit-1.3.1.2: download HUnit-1.3.1.2: configure HUnit-1.3.1.2: build HUnit-1.3.1.2: copy/register
1.3.1.3 Running Haskell REPL without a project
Just run $ stack ghci
outside of a project directory.
$ stack ghci Configuring GHCi with the following packages: GHCi, version 8.0.1: http://www.haskell.org/ghc/ :? for help Loaded GHCi configuration from /tmp/ghci6134/ghci-script Prelude> Prelude> let f x = 10 * x Prelude> f 20 200 Prelude> map f [1, 2, 3, 4, 5] [10,20,30,40,50] Prelude> Prelude> :{ Prelude| mysum :: Double -> Double -> Double Prelude| mysum x y = x + y Prelude| :} Prelude> Prelude> :t mysum mysum :: Double -> Double -> Double Prelude> Prelude> mysum 10.23 20.23 30.46 Prelude>
To pass command line options to ghci run:
$ stack ghci --ghci-options="+RTS -M256m -K256m -RTS"
or
$ stack exec -- ghci +RTS -M256m -K256m -RTS
1.3.1.4 Run a specific GHC version
Run Haskell REPL ghci for LTS resolver 3.22 / ghc-7.10.2. GHC will be installed if it is not available.
$ stack --resolver lts-3.22 --install-ghc ghci
Run Haskell REPL ghci installing a specific version of GHC and installing packages HDBC, HDBC-sqlite3 and random automatically.
$ stack --resolver lts-3.22 --install-ghc ghci --package HDBC --package HDBC-sqlite3 --package random HDBC-sqlite3-2.3.3.1: configure HDBC-sqlite3-2.3.3.1: build HDBC-sqlite3-2.3.3.1: copy/register Configuring GHCi with the following packages: GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help Prelude>
1.3.1.5 Run a Haskell script with specific ghc version:
$ stack --resolver lts-3.22 --install-ghc runghc haskell-script.hs
1.3.1.6 Compile a haskell source code without a project
$ stack ghc Main.hs Module1.hs Module2.hs
or with command line options:
$ stack exec -- ghc Main.hs Module1.hs Module2.hs -o myapp.bin
1.3.1.7 Compile a sources without a project with a specific Haskell version
$ stack --resolver lts-3.22 --install-ghc ghc Main.hs Module1.hs Module2.hs ...
1.3.1.8 Misc
- Install and run a plot library
- Graphics.EasyPlot
- Install GnuPlot (Command for ArchLinux)
$ pacman -S gnuplot
- Run
$ stack --resolver lts-7.19 --install-ghc exec --package easyplot -- ghci
LTS-7.19 - Always runs Haskell 8.0.1
- Plot something.
$ stack --resolver lts-7.19 --install-ghc exec --package easyplot -- ghci GHCi, version 8.0.1: http://www.haskell.org/ghc/ :? for help Prelude> Prelude> import Graphics.EasyPlot Prelude Graphics.EasyPlot> :set prompt "> " > :set prompt2 "- " > > plot X11 $ Gnuplot2D [Color Blue] [] "2**cos(x)" True > plot X11 "x*y" True
- Install and run gtk GUI library
- Install gtk libraries for Arch Linux.
$ sudo pacman -S gobject-introspection gobject-introspection-runtime gtksourceview3 webkitgtk webkit2gtk
- Run:
Get ghci Version:
$ stack --resolver lts-3.22 --install-ghc exec --package gtk -- runhaskell gui1.hs
It installs gtk library and Haskell 7.10.2
File gui1.hs
import Control.Concurrent (forkIO, killThread) import Graphics.UI.Gtk main :: IO () main = do initGUI {---------- Create GUI Widgets -------} -- Create a new Window w <- windowNew set w [windowTitle := "Hello gtk2hs"] windowSetDefaultSize w 300 400 -- Add a button -- b <- buttonNewWithLabel "click me" containerAdd w b {--------- Add Events ---------------} onClicked b (putStrLn "I was clicked !") {--------- Start GUI Loop --------} widgetShowAll w -- Refresh the Window to display the button. mainGUI
- Solve the problem: Ambiguous module name problem
Sample code:
File: gui1.hs
import Graphics.UI.Gtk main :: IO () main = do initGUI window <- windowNew widgetShowAll window onDestroy window mainQuit mainGUI
Problem description
It happens because there are two packages gtk2hs installed gtk (gtk 2.0) and gtk3 (gtk 3.0).
$ stack --resolver lts-3.22 runhaskell /tmp/gui1.hs /tmp/gui1.hs:2:8: Ambiguous module name ‘Graphics.UI.Gtk’: it was found in multiple packages: gtk3-0.14.2@gtk3_AhgiKTeOdGE7p0vrO3qlnB gtk-0.13.9@gtk_DUp9k2RGwvV1yhb3dtjYiE
Solution 1
$ stack --resolver lts-3.22 exec -- ghc-pkg hide gtk3
Running the sample code:
$ stack --resolver lts-3.22 runhaskell /tmp/gui1.hs
Solution 2
An alternative solution is to use the language extension:
{-# language PackageImports #-} import "gtk" Graphics.UI.Gtk main :: IO () main = do initGUI window <- windowNew widgetShowAll window onDestroy window mainQuit mainGUI
For gtk3 package the code would be:
{-# language PackageImports #-} import "gtk3" Graphics.UI.Gtk import "gtk3" Graphics.UI.Gtk.Builder import "gtk3" Graphics.UI.Gtk.Gdk.EventM import Control.Concurrent (forkIO, killThread) main :: IO () main = do initGUI {---------- Create GUI Widgets -------} -- Create a new Window w <- windowNew set w [windowTitle := "Hello gtk2hs"] windowSetDefaultSize w 300 400 -- Add a button -- b <- buttonNewWithLabel "click me" containerAdd w b {--------- Add Events ---------------} onClicked b (putStrLn "I was clicked !") {--------- Start GUI Loop --------} widgetShowAll w -- Refresh the Window to display the button. mainGUI
1.3.2 Build and manage projects with Stack
Stack can install specific versions of packages and Haskell run-time per project in a isolated way avoiding the dependency hell problem, therefore it is possible to have multiple versions of Haskell without them breaking each other.
See:
1.3.3 Exploring Stack
1.3.3.1 Where is ghci ?
$ stack exec -- which ghci /home/arch/.stack/programs/x86_64-linux/ghc-8.0.1/bin/ghci
1.3.3.2 Where is ghc ?
$ stack exec -- which ghc /home/arch/.stack/programs/x86_64-linux/ghc-8.0.1/bin/ghc
1.3.3.3 Show stack search path
$ stack path stack-root: /home/arch/.stack project-root: /home/arch/Documents/projects/zhserver.haskell config-location: /home/arch/Documents/projects/zhserver.haskell/stack.yaml bin-path: /home/arch/.stack/snapshots/x86_64-linux/ghc-8.0.1/8.0.1/bin:/home/arch/.stack/programs/x86_64-linux/ghc-8.0.1/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/home/arch/bin:/home/arch/.local/bin:/home/arch/opt/cling/bin:/home/arch/opt/cling2:/home/arch/opt/fsformatting:/home/arch/opt/gambit-4.8.4/bin:/home/arch/opt/jars:/home/arch/opt/java/bin:/home/arch/opt/jdk/bin:/home/arch/opt/jdk1.8.0_20/bin:/home/arch/opt/maven/bin:/home/arch/opt/scala-2.11.8/bin:/home/arch/opt/vivaldi programs: /home/arch/.stack/programs/x86_64-linux compiler-exe: /home/arch/.stack/programs/x86_64-linux/ghc-8.0.1/bin/ghc compiler-bin: /home/arch/.stack/programs/x86_64-linux/ghc-8.0.1/bin local-bin: /home/arch/.local/bin extra-include-dirs: extra-library-dirs: snapshot-pkg-db: /home/arch/.stack/snapshots/x86_64-linux/ghc-8.0.1/8.0.1/pkgdb local-pkg-db: /home/arch/Documents/projects/zhserver.haskell/.stack-work/install/x86_64-linux/ghc-8.0.1/8.0.1/pkgdb global-pkg-db: /home/arch/.stack/programs/x86_64-linux/ghc-8.0.1/lib/ghc-8.0.1/package.conf.d ghc-package-path: /home/arch/Documents/projects/zhserver.haskell/.stack-work/install/x86_64-linux/ghc-8.0.1/8.0.1/pkgdb:/home/arch/.stack/snapshots/x86_64-linux/ghc-8.0.1/8.0.1/pkgdb:/home/arch/.stack/programs/x86_64-linux/ghc-8.0.1/lib/ghc-8.0.1/package.conf.d snapshot-install-root: /home/arch/.stack/snapshots/x86_64-linux/ghc-8.0.1/8.0.1 local-install-root: /home/arch/Documents/projects/zhserver.haskell/.stack-work/install/x86_64-linux/ghc-8.0.1/8.0.1 snapshot-doc-root: /home/arch/.stack/snapshots/x86_64-linux/ghc-8.0.1/8.0.1/doc local-doc-root: /home/arch/Documents/projects/zhserver.haskell/.stack-work/install/x86_64-linux/ghc-8.0.1/8.0.1/doc dist-dir: .stack-work/dist/x86_64-linux/Cabal-1.24.0.0 local-hpc-root: /home/arch/Documents/projects/zhserver.haskell/.stack-work/install/x86_64-linux/ghc-8.0.1/8.0.1/hpc local-bin-path: /home/arch/.local/bin ghc-paths: /home/arch/.stack/programs/x86_64-linux
Way 1:
$ echo $(stack exec -- bash -c "echo \$PATH") | tr ':' '\n' | grep stack /home/arch/Documents/projects/zhserver.haskell/.stack-work/install/x86_64-linux/lts-8.0/8.0.2/bin /home/arch/.stack/snapshots/x86_64-linux/lts-8.0/8.0.2/bin /home/arch/.stack/programs/x86_64-linux/ghc-8.0.2/bin
1.3.3.4 Show all programs in stack search path
$ echo $(stack exec -- bash -c "echo \$PATH") | tr ':' '\n' | grep stack | xargs ls -l ls: cannot access '/home/arch/Documents/projects/zhserver.haskell/.stack-work/install/x86_64-linux/lts-8.0/8.0.2/bin': No such file or directory /home/arch/.stack/programs/x86_64-linux/ghc-8.0.2/bin: total 72 lrwxrwxrwx 1 arch arch 9 fev 16 10:58 ghc -> ghc-8.0.2 -rwxr-xr-x 1 arch arch 418 fev 16 10:58 ghc-8.0.2 lrwxrwxrwx 1 arch arch 10 fev 16 10:58 ghci -> ghci-8.0.2 -rwxr-xr-x 1 arch arch 100 fev 16 10:58 ghci-8.0.2 lrwxrwxrwx 1 arch arch 13 fev 16 10:58 ghc-pkg -> ghc-pkg-8.0.2 -rwxr-xr-x 1 arch arch 450 fev 16 10:58 ghc-pkg-8.0.2 lrwxrwxrwx 1 arch arch 17 fev 16 10:58 haddock -> haddock-ghc-8.0.2 -rwxr-xr-x 1 arch arch 409 fev 16 10:58 haddock-ghc-8.0.2 -rwxr-xr-x 1 arch arch 42907 fev 16 10:59 hp2ps -rwxr-xr-x 1 arch arch 380 fev 16 10:58 hpc -rwxr-xr-x 1 arch arch 1159 fev 16 10:58 hsc2hs lrwxrwxrwx 1 arch arch 12 fev 16 10:58 runghc -> runghc-8.0.2 -rwxr-xr-x 1 arch arch 426 fev 16 10:58 runghc-8.0.2 lrwxrwxrwx 1 arch arch 6 fev 16 10:58 runhaskell -> runghc /home/arch/.stack/snapshots/x86_64-linux/lts-8.0/8.0.2/bin: total 30164 -rwxr-xr-x 1 arch arch 18205184 fev 16 11:44 cabal -rwxr-xr-x 1 arch arch 12677664 fev 16 11:20 smpl
1.3.3.5 Show stack environment variables
$ stack exec env COLORTERM=truecolor DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-Ubv8WhFbAO,guid=676a06582bbad1b5d87c300b58a87182 DESKTOP_SESSION=xfce DISPLAY=:0.0 DOCKER_HOST=tcp://127.0.0.1:4243 EDITOR=emacs -Q -nw --no-site -eval "(progn (setq inhibit-startup-message t) (global-font-lock-mode t))" GDMSESSION=xfce GHC_PACKAGE_PATH=/home/arch/Documents/projects/zhserver.haskell/.stack-work/install/x86_64-linux/ghc-8.0.1/8.0.1/pkgdb:/home/arch/.stack/snapshots/x86_64-linux/ghc-8.0.1/8.0.1/pkgdb:/home/arch/.stack/programs/x86_64-linux/ghc-8.0.1/lib/ghc-8.0.1/package.conf.d GLADE_CATALOG_PATH=: GLADE_MODULE_PATH=: GLADE_PIXMAP_PATH=: GNOME_KEYRING_CONTROL=/home/arch/.cache/keyring-BEAWVY GTK_MODULES=canberra-gtk-module HASKELL_DIST_DIR=.stack-work/dist/x86_64-linux/Cabal-1.24.0.0 HASKELL_PACKAGE_SANDBOX=/home/arch/.stack/snapshots/x86_64-linux/ghc-8.0.1/8.0.1/pkgdb HASKELL_PACKAGE_SANDBOXES=/home/arch/Documents/projects/zhserver.haskell/.stack-work/install/x86_64-linux/ghc-8.0.1/8.0.1/pkgdb:/home/arch/.stack/snapshots/x86_64-linux/ghc-8.0.1/8.0.1/pkgdb: HOME=/home/arch LANG=en_US.utf8 LC_ADDRESS=pt_BR.UTF-8 LC_IDENTIFICATION=pt_BR.UTF-8 LC_MEASUREMENT=pt_BR.UTF-8 LC_MONETARY=pt_BR.UTF-8 LC_NAME=pt_BR.UTF-8 LC_NUMERIC=pt_BR.UTF-8 LC_PAPER=pt_BR.UTF-8 LC_TELEPHONE=pt_BR.UTF-8 LC_TIME=pt_BR.UTF-8 LOGNAME=arch MAIL=/var/spool/mail/arch MOZ_PLUGIN_PATH=/usr/lib/mozilla/plugins PATH=/home/arch/Documents/projects/zhserver.haskell/.stack-work/install/x86_64-linux/ghc-8.0.1/8.0.1/bin:/home/arch/.stack/snapshots/x86_64-linux/ghc-8.0.1/8.0.1/bin:/home/arch/.stack/programs/x86_64-linux/ghc-8.0.1/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/home/arch/bin:/home/arch/.local/bin:/home/arch/opt/cling/bin:/home/arch/opt/cling2:/home/arch/opt/fsformatting:/home/arch/opt/gambit-4.8.4/bin:/home/arch/opt/jars:/home/arch/opt/java/bin:/home/arch/opt/jdk/bin:/home/arch/opt/jdk1.8.0_20/bin:/home/arch/opt/maven/bin:/home/arch/opt/scala-2.11.8/bin:/home/arch/opt/vivaldi PS1= \[\033[0;31m\]\u\[\033[0;36m\]@\[\033[0;34m\]\h \[\033[0;32m\]\A \[\033[0;36m\]\w\[\033[0;37m\] $ PWD=/home/arch/Documents/projects/zhserver.haskell SHELL=/bin/bash SHLVL=2 STACK_EXE=/usr/bin/stack TERM=xterm-256color USER=arch VISUAL=emacs -Q -nw --no-site -eval "(progn (setq inhibit-startup-message t) (global-font-lock-mode t))" VTE_VERSION=4601 WINDOWID=52514098 XAUTHORITY=/home/arch/.Xauthority XDG_CONFIG_DIRS=/etc/xdg XDG_CURRENT_DESKTOP=XFCE XDG_DATA_DIRS=/usr/local/share:/usr/share XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/arch XDG_MENU_PREFIX=xfce- XDG_RUNTIME_DIR=/run/user/1000 XDG_SEAT=seat0 XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0 XDG_SESSION_COOKIE=arch-pc-1487434114.151435-7060458 XDG_SESSION_DESKTOP=xfce XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0 XDG_SESSION_TYPE=x11 XDG_VTNR=7
1.3.4 Some useful packages
- Commands to install some useful Haskell packages of Haskell Platform - Included Packages
Basic Libraries
$ stack install mtl random turtle conduit async network network uri
Testing libraries:
$ stack install HUnit QuickCheck
Parsing and regex libraries:
$ stack install attoparsec parsec regex-base regex-compat regex-posix
1.4 GHCI Reference
GHCI Interactive Shell
Command | Description |
---|---|
:help | Show help |
:load [haskell-source.hs] or :l src.hs | Load Haskell source code |
:reload or :r | Reload code after it was edited |
:type [expr] or :t [expr] | Show the type of an expression |
:browse | Gives the type signature of all functions in a module |
:set +s | Print timing/memory stats after each evaluation |
:{ [code here ] :} | Multiline code |
:set prompt ">" | Change the prompt to ">" |
:cd [directory] | change the current working directory to [directory] |
:! [shell command>] | execute the shell command; :! pwd print the current directory |
:quit | Quit the interpreter |
See also:
- GHCI configuration file
- GHCI Debugger
- GHC and GHCI Man Page