Damien Gonot
Home Blog Notes About

Haskell

Homepage / Notes / Computer Science / Programming Languages / Haskell

Haskell is:

GHCi

GHCi is an interactive Haskell REPL.

Language Features

Variables

Variables (including names of functions) must always start with a lowercase letter.

name = "Damien"
name
Damien

Types

Types must always start with a capital letter. :: = "has type"

x :: Int

Basic Types

NameDefinition
IntMachine-sized integers
IntegerArbitrary-precision integers
DoubleDouble-precision floating point
BoolBooleans
CharUnicode characters
StringLists of characters with special syntax

Enumeration Types

data Fruit = Banana
           | Strawberry
           | Apple
           | Orange

apple :: Fruit
apple = Apple

Pattern matching on enumeration types:

isRound :: Fruit -> Bool
isRound Banana     = False
isRound Strawberry = False
isRound Apple      = True
isRound Orange     = True

Since function clauses are tried in order from top to bottom, we could make it a bit shorter:

isRound :: Fruit -> Bool
isRound Banana     = False
isRound Strawberry = False
isRound _          = True

Data Constructors

data Person = Person String Int Fruit

damien :: Person
damien = Person "Damien" 30 Banana

getAge :: Person -> Int
getAge (Person _ a _) = a

Numbers

1 + 1
2

(notice the lack of parentheses)

min 9 10
9

Boolean Logic

&& (logical and), || (logical or) and not can be used:

True && False
False
True || False
True
not (True || False)
False

Characters

Characters use single-quotes: 'a'

Strings

Strings are actually lists of characters

reverse "damien"
neimad

Concatenation

"hello" ++ " " ++ "world"
hello world

Putting something at the beginning of a list using : (cons operator) is for efficient

'a':" long string"
a long string

Lists

In Haskell, lists are homogeneous. They can only contain elements of the same types (only integers, or only string).

import Data.List
sort [3,2,1]
[1,2,3]

Accessing Elements by Index

To access an element of a list by index, use !! Indices start at 0

"Damien" !! 2
m
[0,1,2,3] !! 3
3

Head / Tail / Last / Init

head ['a','b','c','d','e']
a
tail ['a','b','c','d','e']
bcde
init ['a','b','c','d','e']
abcd
last ['a','b','c','d','e']
e

Length

length [5,4,3,2,1]
5

Empty List

null checks if a list is empty

null [1,2,3]
False
null []
True

Prepending

0 : [1, 2, 3]
[0,1,2,3]

Concatenation

concat [[1,2], [3,4]]
[1,2,3,4]
[1,2] ++ [3,4]
[1,2,3,4]

Take / Drop

take n list returns the first nth element from list

take 2 [1,2,3,4,5]
[1,2]

drop n list returns list minus the first nth element from list

drop 3 [1,2,3,4,5]
[4,5]

Minimum / Maximum / Sum / Product

minimum [1,2,3,4,5]
1
maximum [1,2,3,4,5]
5
sum [1,2,3]
6
product [3,3,2]
18

Element in List

elem 1 [1,2,3]
True
elem 0 [1,2,3]
False

Usually written as an infix function:

2 `elem` [1,2,3]
True

Map

doubleMe x = x*2
map doubleMe [1,2,3]
[2,4,6]

Filter

filter (\x -> x `mod` 2 == 0) [1..9]
[2,4,6,8]

Foldl

foldl (+) 0 [1,2,3]
6
foldl (-) 0 [1,2,3]
-6

Foldr

foldr (-) 0 [1,2,3]
2

Unfoldr

unfoldr (\x -> if x == 0 then Nothing else Just (x, x-1)) 10
[10,9,8,7,6,5,4,3,2,1]

ConcatMap

concatMap (\x -> [0, x]) [1..3]
[0,1,0,2,0,3]

Conceptually the same as combining concat and map

concat $ map (\x -> [0, x]) [1..3]
[0,1,0,2,0,3]

Scanl

scanl (+) 0 [1..5]
[0,1,3,6,10,15]

The above shows you the "steps" of a sum:

sum [1..5]
15

sortBy

sortBy (\(a,_) (b,_) -> compare a b) [(3, "bananas"), (5, "apples"), (2, "pears")]
[(2,"pears"),(3,"bananas"),(5,"apples")]
import Data.Function
sortBy (compare `on` fst) [(3, "bananas"), (5, "apples"), (2, "pears")]
[(2,"pears"),(3,"bananas"),(5,"apples")]

Tuples

Tuples have a fixed number of elements. The elements of tuples do not need to be of the same type.

(1, True)
(1,True)

Pairs

fst (first)
fst (1, True)
1
snd (second)
snd (1, True)
True

Ranges

[1..10]
[1,2,3,4,5,6,7,8,9,10]

Works for chars too:

['a'..'z']
abcdefghijklmnopqrstuvwxyz

Can specify a "step"

[2,4..20]
[2,4,6,8,10,12,14,16,18,20]

And go backwards

[10,9..0]
[10,9,8,7,6,5,4,3,2,1,0]

Lists can be infinite

take 5 [2,4..]
[2,4,6,8,10]

cycle repeats the same list to infinity

take 10 (cycle [0,1])
[0,1,0,1,0,1,0,1,0,1]

repeat produces an infinite list of a single element

take 10 (repeat 9)
[9,9,9,9,9,9,9,9,9,9]

The above example can be done more simply using replicate

replicate 5 1
[1,1,1,1,1]

List Comprehensions

[x*2 | x <- [1..10]]
[2,4,6,8,10,12,14,16,18,20]
[x*2 | x <- [1..10], x*2 >= 12]
[12,14,16,18,20]

Functions

Function name is followed by parameters separated by spaces

doubleMe x = x + x
doubleMe 2
4
doubleUs x y = x*2 + y*2
doubleUs 2 4
12

To type a function's parameters and output:

doubleMe :: Int -> Int
doubleMe x = x + x
doubleMe 4
8

With multiple parameters:

f :: Int -> Int -> Int -> Int
f x y z = x + y + z
f 1 2 3
6

Anonymous Functions

The \x is supposed to look like a lambda λ

map (\x -> x + 1) [1..3]
[2,3,4]

Infix Operator

Wrapping a function name by backticks (`) turns it into an "infix operator":

19 `mod` 3
1

Above is equivalent to:

mod 19 3
1

Flip

Flips the argument order

concat x y = x ++ " " ++ y
flip concat "damien" "hello"
hello damien

Guards

describeNumber :: Int -> String
describeNumber n
  | n < 0     = "Negative"
  | n == 0    = "Zero"
  | otherwise = "Positive"

Sections

(2^) is equivalent to (^) 2 or \x -> 2 ^ x (^2) is equivalent to flip (^) 2 or \x -> x ^ 2

Examples:

(+1) 1
2
(2*) 2
4

Reverse Application Operator

import Data.Function
1 & (+1)
2
import Data.Function
"Damien" & length
6

Pointfree

let f = (*2)
let g = (^2)
g (f 2)
16
(g . f) 2
16

$ operator

Using example above from point-free programming, parentheses can be removed by adding the $ operator:

g . f $ 2
16

Pattern Matching

An underscore _ can be used as a "wildcard pattern" which matches anything

example = case "Hello" of
           []      -> 3
           ('H':s) -> length s
           _       -> 7
example

Evaluates to 4

Prelude

Haskell's standard module that's imported by default into all modules. Provides definition for commonly used types, classes and functions.

Literate Haskell

https://wiki.haskell.org/Literate_programming

Uses suffix .lhs instead of .hs.

By default, all lines are plain-text.

Single lines of code can be prepended by > to be considered code. For multiple lines, we can surround codes by LaTeX style pairs of \begin{code} and \end{code}.

Web Frameworks

IHP

https://ihp.digitallyinduced.com/

Resources

List of Resources

CIS 194: Introduction to Haskell

https://www.seas.upenn.edu/~cis194/spring13/lectures.html

Real World Haskell

http://book.realworldhaskell.org/read/

Haskell Programming from first principles

https://haskellbook.com/

What I wish I knew when learning Haskell

http://dev.stephendiehl.com/hask/

Programming in Haskell

Book by Graham Hutton

WikiBooks

https://en.wikibooks.org/wiki/Haskell

Learn You a Haskell for Great Good

Used to be recommended a lot, but saw a lot of comments saying it was outdated: http://learnyouahaskell.com/chapters

Plain English explanation about monads

https://chrisdone.com/posts/monads/

The appeal of bidirectional type-checking

https://www.haskellforall.com/2022/06/the-appeal-of-bidirectional-type.html

Data Structures