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

  • load from script, type :l myfunctions
  • change default prompt, :set prompt "ghci> ", or save it to .ghci in home folder

Basics

  • *, / has higher precedence than +, -
  • Boolean algebra: &&, ||, not, ==, /=
  • 5 + "foo" is invalid, 5 + 4.0 is valid, 5 can act like either an integer or a floating-point number.

Functions

  • infix function: function is applied by sandwiching between two arguments, for example 2 * 2.
  • prefix function: function name comes first.
  • if a function takes two parameters, we can call it as infix function by surrounding function name with backticks: ``92 div 10``
  • define a function: doubleMe x = x + x
  • if then else: the else part is mandatory. Haskell's if is an expression that must return a value and not a statement.
  • functions can not begin with capital letters
  • '(apostrophe) is a valid character to use in a function name. It doesn't have any special meaning in syntax but Haskell world usually use ' to denote either a strict version of a function (i.e., one that isn't lazy), or a slightly modified version of a function or variable with similar name.

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

ghci> let foo = [2,4,6,8]
  • concatenation:
    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.
  • accessing list elements:
    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. 
  • lists inside lists
    [[1,2,3],[4,5],[6,7,8,9]]
you can't have a list that contains different types of elements.
  • comparing lists
    ghci> [3,4,2] < [3,4,3]
    True
determined by the first pair of differing elements.
  • more list operations
    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
  • range
    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]
  • list comprehension
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:

  • tuples can store elements of different types
  • tuples have fixed size (immutable)
Search Blog: