Skip to content

Latest commit

 

History

History
639 lines (477 loc) · 22.5 KB

Haskell.org

File metadata and controls

639 lines (477 loc) · 22.5 KB

Setting up a Haskell Development Environment

Haskell

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 CompilerTransforms Haskell Source code .hs into native code.
ghciHaskell Interactive Shell / Interpreter
runghcHaskell Non Interactive Interpreter
haddockDocumentation tool for annotated Haskell source code
cabalGHC Haskell Cabal building tool
stackHaskell new package manager and building automation tool.

Suffixes of file names for Haskell

ExtensionDescription
Source File
.hsHaskell source code; preprocess, compile
.lhsliterate Haskell source; unlit, preprocess, compile
Compilation output
.hiInterface file; contains information about exported symbols
.hcintermediate C files
.x_oway x object files; common ways are: p, u, s
.x_hiway x interface files

Setting up a Haskell Development Environment

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

Text editor

Atom

Emacs

Haskell stack tool

Using stack without a project

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 / ResolverHaskell Version
lts-8.3GHC 8.0.2
lts-7.19GHC 8.0.1
lts-6.30GHC 7.10.3
lts-3.22GHC 7.10.2
lts-2.22GHC 7.8.4
lts-0.7GHC 7.8.3

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

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

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> 

Run a Haskell script with specific ghc version:

$ stack --resolver lts-3.22 --install-ghc runghc haskell-script.hs

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 

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 ...

Misc

Install and run a plot library
  1. Install GnuPlot (Command for ArchLinux)
$ pacman -S gnuplot 
  1. Run
$ stack --resolver lts-7.19 --install-ghc exec --package easyplot -- ghci

LTS-7.19 - Always runs Haskell 8.0.1

  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
  1. Install gtk libraries for Arch Linux.
$ sudo pacman -S gobject-introspection gobject-introspection-runtime gtksourceview3 webkitgtk webkit2gtk
  1. 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    

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:

Exploring Stack

Where is ghci ?

$ stack exec -- which ghci
/home/arch/.stack/programs/x86_64-linux/ghc-8.0.1/bin/ghci

Where is ghc ?

$ stack exec -- which ghc
/home/arch/.stack/programs/x86_64-linux/ghc-8.0.1/bin/ghc

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

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

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

Some useful 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

GHCI Reference

GHCI Interactive Shell

CommandDescription
:helpShow help
:load [haskell-source.hs] or :l src.hsLoad Haskell source code
:reload or :rReload code after it was edited
:type [expr] or :t [expr]Show the type of an expression
:browseGives the type signature of all functions in a module
:set +sPrint 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
:quitQuit the interpreter

See also: