Haskell
Homepage / Notes / Computer Science / Programming Languages / Haskell
Haskell is:
- Functional: functions are first-class and programs are centered around evaluating expressions
- Pure: everything is immutable, expressions never have side effects, calling the same function with the same arguments always results in the same output
- Lazy: expressions are not evaluated until their results are actually needed
- Statistically typed: every Haskell expression has a type and types are all checked at compile time
GHCi
GHCi is an interactive Haskell REPL.
Language Features
Variables
Variables (including names of functions) must always start with a lowercase letter.
name = "Damien"
nameDamien
Types
Types must always start with a capital letter. :: = "has type"
x :: IntBasic Types
| Name | Definition |
|---|---|
| Int | Machine-sized integers |
| Integer | Arbitrary-precision integers |
| Double | Double-precision floating point |
| Bool | Booleans |
| Char | Unicode characters |
| String | Lists of characters with special syntax |
Enumeration Types
data Fruit = Banana
| Strawberry
| Apple
| Orange
apple :: Fruit
apple = ApplePattern matching on enumeration types:
isRound :: Fruit -> Bool
isRound Banana = False
isRound Strawberry = False
isRound Apple = True
isRound Orange = TrueSince 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 _ = TrueData Constructors
data Person = Person String Int Fruit
damien :: Person
damien = Person "Damien" 30 Banana
getAge :: Person -> Int
getAge (Person _ a _) = aNumbers
1 + 12
(notice the lack of parentheses)
min 9 109
Boolean Logic
&& (logical and), || (logical or) and not can be used:
True && FalseFalse
True || FalseTrue
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" !! 2m
[0,1,2,3] !! 33
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 24
doubleUs x y = x*2 + y*2
doubleUs 2 412
To type a function's parameters and output:
doubleMe :: Int -> Int
doubleMe x = x + x
doubleMe 48
With multiple parameters:
f :: Int -> Int -> Int -> Int
f x y z = x + y + z
f 1 2 36
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` 31
Above is equivalent to:
mod 19 31
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) 12
(2*) 24
Reverse Application Operator
import Data.Function
1 & (+1)2
import Data.Function
"Damien" & length6
Pointfree
let f = (*2)
let g = (^2)g (f 2)16
(g . f) 216
$ operator
Using example above from point-free programming, parentheses can be removed by adding the $ operator:
g . f $ 216
Pattern Matching
An underscore _ can be used as a "wildcard pattern" which matches anything
example = case "Hello" of
[] -> 3
('H':s) -> length s
_ -> 7
exampleEvaluates 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
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