In order to get started with programming in Haskell, you will need a Linux/Ubuntu terminal. Haskell is supported on Windows, but the Nix package manager that we will be using currently lacks native Windows support. You have the following options for using Linux/Ubuntu:
- Windows Subsystem for Linux (WSL2) (Recommended)
- Install an Ubuntu Virtual Machine
- Dual-boot Ubuntu OR NixOS
Once you complete one of the steps above, open up your Terminal application to get started.
If you've never used a terminal before, don't worry! The terminal is what developers use to interact with their computers operating system. It gives us access to a bunch of commands that allow us to configure and control our computers with ease. Check out this guide on how to use a Linux Terminal. Use a cheat sheet if you forget the common linux commands, and don't be afraid to look them up when you need them.
Nix is a powerful package manager that ensures reproducible builds. We’ll use it to install Haskell tooling and manage dependencies.
To install Nix, run the following command in your terminal:
sh <(curl -L https://nixos.org/nix/install) --daemon
Once installed, make sure your environment is set up by restarting your terminal or running:
. ~/.nix-profile/etc/profile.d/nix.sh
Now, you’re ready to use Nix to install GHC and GHCi.
To get started, we will create a simple shell.nix file that will configure our development environment. Create a directory for your Haskell project:
mkdir my-haskell-project
cd my-haskell-project
Create a file named shell.nix with the following content:
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [
pkgs.haskellPackages.ghc
pkgs.haskellPackages.cabal-install
];
}
This file ensures that when you enter the directory, Nix will provide GHC and Cabal for compiling and running Haskell code.
To activate the environment, run:
nix-shell
You are now in a Nix shell with GHC and Cabal installed!
With GHCi installed, you can start an interactive session by simply typing:
ghci
This starts the Haskell REPL, where you can interactively write and evaluate Haskell expressions.
Example:
Prelude> 2 + 3
5
This will immediately output 5. The REPL is a great tool for testing and experimenting with Haskell code.
Haskell has a strong, statically-typed system. Every expression has a type, and you can check the type of an expression using the :type (or :t) command in GHCi.
Example:
Prelude> :type 42
42 :: Integer
Prelude> :type "Hello"
"Hello" :: [Char]
Prelude> :type not
not :: Bool -> Bool
Here, you can see that 42 is an Integer, "Hello" is a list of characters ([Char]), and not is a function that takes a Bool and returns a Bool.
You can also define functions directly in GHCi or in a Haskell file:
Prelude> let add x y = x + y
Prelude> add 3 4
7
This defines a simple add function that takes two arguments and adds them.
To check the type of the function:
Prelude> :type add
add :: Num a => a -> a -> a
This tells us that add works for any type a that is part of the Num typeclass, i.e., a numeric type.
Instead of typing everything into GHCi, you can write code in a file and load it. Let’s say you have a file called Main.hs:
-- Main.hs
add :: Int -> Int -> Int
add x y = x + y
main :: IO ()
main = print (add 3 4)
To load this file in GHCi, simply run:
ghci Main.hs
Now, you can use the functions defined in the file:
Prelude> main
7
Prelude> add 2 3
5
If you make changes to the file, you can reload it in GHCi using:
:reload
Or simply :r
.
Haskell’s strong type system means that many errors are caught at compile time. Understanding these errors is key to improving your Haskell skills.
Example Error:
Let’s say we write this incorrect code in Main.hs:
add :: Int -> Int -> Int
add x y = x + "Hello"
When you try to load this file, you’ll get an error message:
Main.hs:2:14: error:
• No instance for (Num [Char]) arising from a use of ‘+’
• In the expression: x + "Hello"
In an equation for ‘add’: add x y = x + "Hello"
This error occurs because we are trying to add an Int (x) to a String ("Hello"), which is not allowed. The error message “No instance for (Num [Char])” means that Haskell expected a number (Num), but it found a list of characters ([Char], which is a string).
To fix this, we change the code to:
add :: Int -> Int -> Int
add x y = x + y
Now the function works as expected.
Cabal is a Haskell build tool that manages dependencies and builds your Haskell projects. You can use Cabal with Nix by adding dependencies in a .cabal file.
Run the following to initialize a new project:
cabal init
This will guide you through the setup of a new Haskell project. After setup, you can run the project with:
cabal build
cabal run
Cabal ensures that all dependencies are handled, and the code is compiled correctly.
Here are some key GHCi commands to help you along the way:
:load (or :l)
: Load a Haskell file.:reload (or :r)
: Reload the current file.:type (or :t)
: Check the type of an expression.:info (or :i)
: Get information about a function or type.:quit (or :q)
: Exit GHCi.
Let’s write a simple Haskell program to interact with the user. Create a file called Greeting.hs:
-- Greeting.hs
main :: IO ()
main = do
putStrLn "What's your name?"
name <- getLine
putStrLn ("Hello, " ++ name ++ "!")
You can load and run this program in GHCi:
ghci Greeting.hs
Prelude> main
What's your name?
John
Hello, John!