Jim Cheung

Learn you a Haskell for great good

Functional Programming You don't tell the computer what to do, you tell it what stuff is.

Purely functional languages, a function has no side effects. It guaranteed to return same result every time it is called. This property is called referential transparency.

Haskell is purely functional language.

Haskell is lazy. It means that unless specifically told otherwise it won't execute functions.

Haskell is statically typed. Type error is caught at compile time. Haskell has a type inference type system, you don't need to explicitly label everything with type, the system will figure it out.

GHC interactive mode

Basics

Functions

Lists Lists in Haskell are homogeneous data structures, only elements with same type can be stored together.

ghci> let foo = [2,4,6,8]
    ghci> [1,2,3,4] ++ [5,6,7,8]
    [1,2,3,4,5,6,7,8]
    ghci> ['w','o'] ++ ['o','t']
    "woot"
In Haskell, *strings* are just lists of characters, we can use list functions on strings.
    ghci> 'A':" SMALL CAT"
    "A SMALL CAT"
    ghci> 5:[1,2,3]
    [5,1,2,3]
`++` takes two lists but `:` takes a single item and a list. `[1,2,3] ++ 5` is wrong, we need to do: 
    ghci> [1,2,3] ++ [5]
    [1,2,3,5]
In Haskell, `[1,2,3]` is just syntactic sugar for `1:2:3:[]`
`[]`, `[[]]` and `[[],[]]` are all different. The first is an empty list, 2nd is a list contains one empty list, 3rd is a list contains 2 empty lists.
    ghci> "Steve Buscemi" !! 6
    'B'
    ghci> [2,3,4,5] !! 1
    3
you'll get an error if you try to get the 6th element from a list with only 4 elements. 
    [[1,2,3],[4,5],[6,7,8,9]]
you can't have a list that contains different types of elements.
    ghci> [3,4,2] < [3,4,3]
    True
determined by the first pair of differing elements.
    ghci> head [5,4,3,2,1]
    5
    ghci> tail [5,4,3,2,1]
    [4,3,2,1]
    ghci> last [5,4,3,2,1]
    1
    ghci> init [5,4,3,2,1]
    [5,4,3,2]
    ghci> length [5,4,3,2,1]
    5
    ghci> null [5,4,3,2,1]
    False
    ghci> null []
    True
    ghci> reverse [5,4,3,2,1]
    [1,2,3,4,5]
    ghci> take 3 [5,4,3,2,1]
    [5,4,3]
    ghci> take 10 [5,4,3,2,1]
    [5,4,3,2,1]
    ghci> take 0 [5,4,3,2,1]
    []
    ghci> drop 3 [5,4,3,2,1]
    [2,1]
    ghci> drop 10 [5,4,3,2,1]
    []
    ghci> maximum [5,4,3,2,1]
    5
    ghci> minimum [5,4,3,2,1]
    1
    ghci> sum [5,4,3,2,1]
    15
    ghci> product [5,4,3,2,1]
    120
    ghci> elem 4 [5,4,3,2,1]
    True
    ghci> 0 `elem` [5,4,3,2,1]
    False
    ghci> [1..20]
    ghci> ['a'..'z']
    ghci> ['K'..'Z']
    
    ghci> [2,4..10]
    [2,4,6,8,10]
    ghci> [3,6..10]
    [3,6,9]
you can also make an infinite list by not specifying an upper limit.
    ghci> [13,26..24*13]
but a better way to do it is using a infinite list:
    ghci> take 24 [13,26..]
Haskell is *lazy*, it won't try to evaluate the entire list immediately, it will wait and see which elements you need to get from the list.
functions that can be used to produce long or infinite lists:
  • - cycle
ghci> take 12 (cycle "LOL ") "LOL LOL LOL "
  • - repeat
ghci> take 4 (repeat 5) [5,5,5,5]
  • - replicate
ghci> replicate 3 10 [10,10,10] careful with floating point ranges, because they only have finite precision, result is not predictable: ghci> [0.1, 0.3 .. 1] [0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]
for set comprehension <code>{2 ∙ x | x ∈ N, x ≤ 10}</code> (take all natural numbers less than or equal to 10, multiply each one by 2, use results to create a new set): 
    ghci> [x*2 | x <- [1..10]]
    [2,4,6,8,10,12,14,16,18,20]
add condition (*predicate*), let's say, we want only elements are greater than or equal to 12 after being doubled:
    ghci> [x*2 | x <- [1..10], x*2 >= 12]
    [12,14,16,18,20]
    ghci> [if x < 10 then "BOOM!" else "BANG!" | x <- [7..13], odd x]
    ["BOOM!","BOOM!","BANG!","BANG!"]
we can include as many predicates as we want, all separated by commas:
    ghci> [x | x <- [10..20], x /= 13, x /= 15, x /= 19]
    [10,11,12,14,16,17,18,20]
from multiple lists:
    ghci> [x+y | x <- [1,2,3], y <-[10,100,1000]]
    [11,101,1001,12,102,1002,13,103,1003]
write a length function
    ghci> let length' xs = sum [1 | _ <- xs]
    ghci> length' [1,2,3,4,5]
    5
`_` doesn't have special meaning, just a name for temporary variable.
a function to remove all non-upper case characters:
    ghci> let removeNonUppercase st = [c | c <- st, c `elem` ['A'..'Z']]

Tuples difference between tuples and lists: