Pure Functional Programming with Haskell

Concepts of Programming Languages

Sebastian Macke

Rosenheim Technical University

Last lecture

2

Recap: Pure Functions

3

What is a pure function?

Examples: exp, sin, cos, max, min.

Advantages

4

Recap: Functional Programming – Characteristics

The most prominent characteristics of functional programming are as follows

5

Recap: Functional programming offers the following advantages

Functional programming does not support state, so there are no side-effect results and we can write error-free codes.

Functional programs consist of independent units that can run concurrently. As a result, such programs can be more efficient.

Functional programming supports lazy evaluation like Lazy Lists, Lazy Maps, etc.

Functional programming supports distributed computing

6

Haskell

7

Ranking

8

Websites to experiment with Hakell

Online tutorials

9

Haskell I: Hello world

main = print "Hello, World!"

1. Define a function with name "main" with no input and output parameters.
Execute the function print, which takes one arbitrary argument. In this case a string

Online editor:

10

Haskell: Type System

2 + 15                 => 17
40 * 100               => 4900
5 == 5                 => True
5 == 5.0               => True
True && False          => False
not False              => True
"Hello" ++ " World"    => "Hello World"
[1,2,3] ++ [4,5,6]     => [1,2,3,4,5,6]
[1,2,3] !! 1           => 2
"hey" == ['h','e','y'] => True  -- Strings are just lists of characters
"hey" !! 0             => 'h'
11

Haskell: Variables

r = 5 -- globally defined variable
main = do
       let n = r  -- local defined "variable"
       print n
       let m = n + 1
       print m

The do keyword is used to define a block of code. This sequence of instructions nearly
matches that in any imperative language

Actually a variable is just a function with no arguments

12

Haskell: Functions

Defines a function inc that takes one argument x and returns x + 1

inc x = x + 1
main = print (inc 1)
inc x = x + 1
main = print $ inc 1

The $ operator is used to avoid parentheses. It has the lowest precedence of all operators

13

Haskell: Partial Applications

Function, which takes multiple arguments, can be partially applied
Here, the function add takes two arguments a and b and returns a + b

add a b = a + b
main = print $ add 1 2
add a b = a + b
main = do
       let c = add 1 -- partial application
       print $ c 2
add a b = a + b
main = print( (add 1) 2)
14

The return function

TODO

15

Haskell: Type signatures

add :: Int -> Int -> Int
add a b = a + b
main = print $ add 1 2
add :: Int -> (Int -> Int)
16

Haskell: Functional Composition

square x = x * x
tripleSquare = square . square . square
main = print $ tripleSquare 2 -- returns 256
17

Haskell: Control Flow

max a b = if a > b then a else b
main = print $ Main.max 1 2  -- max already exists, so be more specific
max a b | a > b = a
        | otherwise = b
main = print $ Main.max 1 2 -- max already exists, so be more specific
18

Excercise

19

Haskell: Recursions

factorial n = if n < 2
              then 1
              else n * factorial (n - 1)

main = print $ factorial 10
factorial 0 = 1
factorial n = n * factorial (n - 1)
main = print (factorial 10)
20

Haskell: Tuples

Haskell uses two fundamental structures for managing several values: lists and tuples.
They both work by grouping multiple values into a single combined value.

addsub a b = (a + b, a - b)
main = print $ addsub 1 2
add a b = (a + b, a - b)
main = do
      let (x, y) = add 1 2
      print x; print y
      print $ fst (add 1 2) -- first element
      print $ snd (add 1 2) -- second element
21

Haskell: Lists

main = do
     print [1,2,3]
     print (1:2:3:[])    -- same as [1,2,3]
     print [1 .. 3]      -- same as [1,2,3]
     print ([1,2,3] ++ [4,5,6])
     print $ [1,2,3] !! 1 -- access element at index 1
     print $ head [1,2,3] -- first element
     print $ tail [1,2,3] -- all elements except the first one
     print $ last [1,2,3] -- last element
     print $ init [1,2,3] -- all elements except the last one
22

Haskell: Functional usage of lists

myhead (x:xs) = x
mytail (x:xs) = xs
main = do
       print $ myhead [1,2,3]
       print $ mytail [1,2,3]

(x:xs) is a pattern that matches a list with at least one element

23

Haskell: Functional usage of lists

reverse [] = []
reverse (x:xs) = Main.reverse xs ++ [x]
main = print $ Main.reverse [1,2,3]
isPalindrome [] = True
isPalindrome [x] = True
isPalindrome (x:xs) = x == (last xs) && isPalindrome (init xs)
main = print $ isPalindrome [1,2,3,2,1]
24

Haskell: Functional Composition with Lists

import Data.List
revsort = (reverse . sort)
main = print $ revsort [2,8,7,10,1,9,5,3,4,6]

1. Sort takes a list and returns a sorted list. The result of sort is pipelined to reverse
2. prints the result of revsort for the given table

25

Haskell: Lazy evaluation

osc :: [Integer]
osc = 0 : 1 : osc
main = print (osc!!10)

1. Define a function osc, which returns a list of integers of unknown size
2. Define a function osc, which returns oscillating numbers 0,1,0,1,0,1. There is no break condition in this list!
3. Execute the function fibs which actually should return an infinite list. But is not evaluated yet.
Take the 10th element out of the list. Print the result

This example explains the concept of lazy evaluation.
The list osc is not evaluated until it is needed.
The function osc is called only once, but the list osc is evaluated many times.
The list osc is evaluated only as much as needed.

26

Higher Order Functions

map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs

main = print $ map (+1) [1,2,3]
add x y = x + y

map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : Main.map f xs

main = print $ Main.map (add 1) [1,2,3]
27

Finally: The quicksort algorithm by using the filter function

With the filter function

main = print $ filter (<3) [4,3,2,1,2,3,4]    -- returns [2,1,2]

we can finally define the famous quicksort algorithm

quickSort []     = []
quickSort (x:xs) = quickSort (filter (<x) xs)
                   ++ [x] ++
                   quickSort (filter (>=x) xs)
main = print $ quickSort [2,8,7,10,1,9,5,3,4,6]
28

Communication with the outside world

Also Haskell have to perform IO

import Data.Time.Clock
import Control.Concurrent

main :: IO ()   -- return type is IO (). The function is executed regardless of the return value
main = do
  x <- getCurrentTime;
  print x;
  threadDelay 1000000;
  x <- getCurrentTime;
  print x

The <- sign is used to assign the result of a non-pure function to a variable

29

Exercise 6

30

Thank you

Sebastian Macke

Rosenheim Technical University

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)