Homepage / Notes / Computer Science / Programming Languages / Haskell
Haskell is:
GHCi is an interactive Haskell REPL.
Variables (including names of functions) must always start with a lowercase letter.
= "Damien"
name name
Damien
Types must always start with a capital letter. ::
= "has type"
x :: Int
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 |
data Fruit = Banana
| Strawberry
| Apple
| Orange
apple :: Fruit
= Apple apple
Pattern matching on enumeration types:
isRound :: Fruit -> Bool
Banana = False
isRound Strawberry = False
isRound Apple = True
isRound Orange = True isRound
Since function clauses are tried in order from top to bottom, we could make it a bit shorter:
isRound :: Fruit -> Bool
Banana = False
isRound Strawberry = False
isRound = True isRound _
data Person = Person String Int Fruit
damien :: Person
= Person "Damien" 30 Banana
damien
getAge :: Person -> Int
Person _ a _) = a getAge (
1 + 1
2
(notice the lack of parentheses)
min 9 10
9
&&
(logical and), ||
(logical or) and not
can be used:
True && False
False
True || False
True
not (True || False)
False
Characters use single-quotes: 'a'
Strings are actually lists of characters
reverse "damien"
neimad
"hello" ++ " " ++ "world"
hello world
Putting something at the beginning of a list using :
(cons operator) is for efficient
'a':" long string"
a long string
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]
To access an element of a list by index, use !!
Indices start at 0
"Damien" !! 2
m
0,1,2,3] !! 3 [
3
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 [5,4,3,2,1]
5
null
checks if a list is empty
null [1,2,3]
False
null []
True
0 : [1, 2, 3]
[0,1,2,3]
concat [[1,2], [3,4]]
[1,2,3,4]
1,2] ++ [3,4] [
[1,2,3,4]
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 [1,2,3,4,5]
1
maximum [1,2,3,4,5]
5
sum [1,2,3]
6
product [3,3,2]
18
elem 1 [1,2,3]
True
elem 0 [1,2,3]
False
Usually written as an infix function:
2 `elem` [1,2,3]
True
= x*2
doubleMe x map doubleMe [1,2,3]
[2,4,6]
filter (\x -> x `mod` 2 == 0) [1..9]
[2,4,6,8]
foldl (+) 0 [1,2,3]
6
foldl (-) 0 [1,2,3]
-6
foldr (-) 0 [1,2,3]
2
-> if x == 0 then Nothing else Just (x, x-1)) 10 unfoldr (\x
[10,9,8,7,6,5,4,3,2,1]
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 (+) 0 [1..5]
[0,1,3,6,10,15]
The above shows you the "steps" of a sum:
sum [1..5]
15
-> compare a b) [(3, "bananas"), (5, "apples"), (2, "pears")] sortBy (\(a,_) (b,_)
[(2,"pears"),(3,"bananas"),(5,"apples")]
import Data.Function
compare `on` fst) [(3, "bananas"), (5, "apples"), (2, "pears")] sortBy (
[(2,"pears"),(3,"bananas"),(5,"apples")]
Tuples have a fixed number of elements. The elements of tuples do not need to be of the same type.
1, True) (
(1,True)
fst (1, True)
1
snd (1, True)
True
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]
*2 | x <- [1..10]] [x
[2,4,6,8,10,12,14,16,18,20]
*2 | x <- [1..10], x*2 >= 12] [x
[12,14,16,18,20]
Function name is followed by parameters separated by spaces
= x + x
doubleMe x 2 doubleMe
4
= x*2 + y*2
doubleUs x y 2 4 doubleUs
12
To type a function's parameters and output:
doubleMe :: Int -> Int
= x + x
doubleMe x 4 doubleMe
8
With multiple parameters:
f :: Int -> Int -> Int -> Int
= x + y + z
f x y z 1 2 3 f
6
The \x
is supposed to look like a lambda λ
map (\x -> x + 1) [1..3]
[2,3,4]
Wrapping a function name by backticks (`
) turns it into an "infix operator":
19 `mod` 3
1
Above is equivalent to:
mod 19 3
1
Flips the argument order
concat x y = x ++ " " ++ y
flip concat "damien" "hello"
hello damien
describeNumber :: Int -> String
describeNumber n| n < 0 = "Negative"
| n == 0 = "Zero"
| otherwise = "Positive"
(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
import Data.Function
1 & (+1)
2
import Data.Function
"Damien" & length
6
let f = (*2)
let g = (^2)
2) g (f
16
. f) 2 (g
16
Using example above from point-free programming, parentheses can be removed by adding the $
operator:
. f $ 2 g
16
An underscore _
can be used as a "wildcard pattern" which matches anything
= case "Hello" of
example -> 3
[] 'H':s) -> length s
(-> 7
_ example
Evaluates to 4
Haskell's standard module that's imported by default into all modules. Provides definition for commonly used types, classes and functions.
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}
.
https://ihp.digitallyinduced.com/
https://www.seas.upenn.edu/~cis194/spring13/lectures.html
http://book.realworldhaskell.org/read/
http://dev.stephendiehl.com/hask/
Book by Graham Hutton
https://en.wikibooks.org/wiki/Haskell
Used to be recommended a lot, but saw a lot of comments saying it was outdated: http://learnyouahaskell.com/chapters
https://chrisdone.com/posts/monads/
https://www.haskellforall.com/2022/06/the-appeal-of-bidirectional-type.html