Functional Programming Charlie Li 6/4/2019 Content

• Haskell – Features • Haskell – Basic Types • Haskell – Classes • Haskell – Custom Types • Haskell – Infix Function • Haskell – Precedence and Associativity • Haskell – Partial Application Content

• Haskell – Strict Type • Haskell – Syntax • Haskell – • Haskell – Lists • Haskell – Folds • Haskell – Tuples • Haskell – Challenges • Haskell – More Functional Programing

• Why functional programing?

• Pros: • Less bug • Shorter and cleaner code • Focus on WHAT to calculate not HOW to calculate

• Cons: • Looonger programming time and runtime • Compile errorsss Functional Programing

• Pure function • A pure function is a function which gives the same result with the same input • No side effects • Outputting to screen is a side effect! Functional Programing

• Which of the following functions are pure functions? void f1() { cout << "Hello World !" << endl; } int f2(int x) { return ++x; } int f3(int& x) { return ++x; } int f4(int x, int y) { return x + y; } Functional Programing

• f1 is not a pure function!

• It print the same string every time, isn’t it a constant function?

• No, printing is a side effect, it changes your screen! • More precisely, it changes some part of the memory that does not belong to it Functional Programing

• f2 is a pure function!

• It has not side effects.

• Although it changes the variable x, that x belongs to the function, not the outside world, so it is pure Functional Programing

• f3 is not a pure function!

• It has side effect.

• Noted that x is passed by reference. • It changes the variable x which does not belong to itself Functional Programing

• f4 is a pure function!

• It has no side effects.

• It returns the same output when the input is the same. Functional Programing

• In a pure functional programing language, every function is a pure function • All variables are mathematically variables • It has , i.e. replacing the variable by its value does not change the behavior of the program • Global variables are essentially global constant • No input and output in the function • IO is troublesome and too difficult to be explained today Haskell - Features

• Haskell is a pure functional programming language • Every function is a pure function

• Haskell is statically typed • The type of variables are determined at compile time

• Haskell supports type inference • The compile can detect the type of variables and functions even if it is not provided

• Haskell supports • The value of an expression is evaluated only if it is needed Haskell – Basic Types

• Names of data types always starts with capital letter

• Some basic types are: • Int • A 32-bit or 64-bit integer, depends on computer • Integer • Aka. Big integer • Double • Char • Bool • String Haskell – Basic Types

• There are also two more kind of useful data types in Haskell

• Lists • Every element are of the same type in a list (unlike Python) • There is no restriction on the length of lists • Yes, there are lists with infinite length

• Tuples • Elements in a tuple may have different types • The largest tuple can have up to 62 entries Haskell – Basic Types

• Lists • List are represented using brackets [] • [1, 2, 3] is a list of integer with length 3 • Its type maybe [Int] or [Double] or …

• Tuples • Tuples are represented using parenthesis () • (1, ‘a’, [True, False]) is a tuple with three element • Its type maybe (Int, Char, [Bool]) or (Double, Char, [Bool]) or … Haskell Platform

• Haskell Platform includes GHC (the Haskell compiler) and other useful tools

• The latest version is 8.6.3, the installer for Windows can be downloaded here • You can find the download links for other OS at the bottom Haskell – Area

• Let’s open ghci (winghci has better UI but cannot be used in this lab due to some permission issues) • Let’s first define a function to calculate the area of a rectangle

• Type the following into ghci (let areaRect l w = l * w):

• This is the definition of the function areaRect

• What do you think will be the output of areaRect 2 3? Haskell – Area

• Bingo

• How about areaRect 2.5 3.5? Haskell – Area

• Bingo

• Next question, how about areaRect 2.5 3? Haskell – Area

• Bingo

• Next question, what do you think will be the type of areaRect? • Sometimes it takes two integers as input and return integer • Sometimes it takes two fractional numbers as input and return a fractional number Haskell – Area

• In ghci, we can type :t name to check the type (aka. signature) of a function

• The “::” tells that the following is the function type not a definition

• The “Num a =>” part says that a is a type that belongs to the “Num” class • “Num” class contains all kinds of numbers, e.g. Int, Integer, Float, Double, … Haskell – Area

• In ghci, we can type :t name to check the type (aka. signature) of a function

• The “a -> a -> a” part is the type of the function • The last one is the type of the returned value • Others are the type of parameter • So area takes two parameter with the same type as input and return the same type • Also, this a must be some kind of number Haskell – Area

• In ghci, we can type :t name to check the type (aka. signature) of a function

• So this tells us that areaRect is a function that takes two numbers as input and return a number Haskell – Classes

• Be careful, there is a bit difference between class and type

• Haskell is a statically typed language • The existence of class is for safe function overload

• There are similarity between class in Haskell and class in ++ • There are some inheritance relation • E.g. Integral a => Num a • But the class in Haskell is not the same as the class in C++ Haskell – Classes

• There are many predefined classes in Haskell, the name are usually descriptive enough Haskell – Classes

• Eq: All types that == and /= are defined • Ord: All types that <, >, <=, >= are defined • Num: All types of numbers • Real: All types of real numbers • Fractional: All types of numbers that are not necessarily integer • Integral: All types of integers • Foldable: All types that “foldr” is defined • Read: All types that “read” is defined • Show: All types that “show” is defined • … Haskell – Classes

• So now do you know the type of [1, 2, 3] and (1, ‘a’, [True, False]) ?

• How to check if you get the correct answer? • Just try to type :t [1, 2, 3] and :t (1, ‘a’, [True, False]) Haskell – Classes

• Did you get it right? Haskell – Custom Type

• In Haskell you can define your own type • Syntax like this: data Contact = Phone Integer | Email String data Maybe a = Just a | Nothing data Either a b = Left a | Right b data Ordering = LT | EQ | GT

• Phone, Email, … are said to be the constructors of the corresponding type • Maybe, Either and Ordering are predefined in Haskell Haskell – Custom Type

• You can use Notepad++ to write the code and save as “.hs”

• Suppose your code is saved as “C:\Haskell\code\sample.hs” • You need to type the following to load the code into ghci :load C:\Haskell\code\sample.hs

• You will see the “Prelude” become “Main” if it is loaded successfully Haskell – Custom Type

• Phone and Email are constructors of Contact • They are also functions with the following type Haskell – Custom Type data Contact = Phone Integer | Email String data Maybe a = Just a | Nothing data Either a b = Left a | Right b data Ordering = LT | EQ | GT

• Maybe, Either are kinds and NOT classes nor types • Contact, Maybe Int are types • Phone 98765432, Just 0, Nothing are values Haskell – Infix Function

• A function with symbol only is assumed to be infix operator • Need to add a pair of brackets to make it like normal functions

-- x + y == (+) x y

• A function can become infix if it is wrapped by `` add x y = x + y -- add x y == x `add` y Haskell – Precedence and Associativity

• Infix functions has lower precedence then normal functions • Normal functions are left associated • i.e. f a b == (f a) b • Associativity of infix functions depend on the function • Usually left associated • Some right associated functions: exponent, (.), ($) ($) :: (a -> b) -> a -> b -- trick: f $ g $ h x == f (g (h x)) /= ((f g) h) x == f g h x Haskell – Anonymous Function

• In Haskell, it is able to define anonymous function using lambda expression.

• Syntax: \var1 var2 … varn -> expression • The expression goes as far as possible • Remember to add parentheses • Example: \x -> x + 1 \x y -> x + y Haskell – Anonymous Function

• Remember when will you use anonymous function in C++? sort(v.begin(), v.end(), [] (int x, int y) { return x > y; }); • You can also write something similar in Haskell • There is a sortBy function in Haskell (in the package Data.List) • To import Data.List into ghci, simply type import Data.List sort :: Ord a => [a] -> [a] sortBy :: (a -> a -> Ordering) -> [a] -> [a] Haskell – Anonymous Function sort [1, 4, 2, 3] -- [1, 2, 3, 4] sortBy (\x y -> negate x `compare` negate y) [1, 4, 2, 3] -- [4, 3, 2, 1]

-- negate :: Num a => a -> a -- compare :: Ord a => a -> a -> Ordering -- *this is not the best way to define it, why? Haskell – Unary Functions

• Actually all functions can be viewed as unary functions • How about (+) which takes two parameter?

(+) :: Num a => a -> a -> a -- can be viewed as (+) :: Num a => a -> (a -> a) -- (+) x == \y -> x + y

• (->) is right associative • (+) takes one input (number) and returns one output (function) Haskell – Partial Application

• Consider add x y = x + y addTwo = add 2

• What is the type of addTwo?

• This is called partial application. Haskell – Partial Application

• Here comes some function that are often applied partially const :: a -> b -> a -- usually be viewed as const :: a -> (b -> a) flip :: (a -> b -> c) -> b -> a -> c -- usually be viewed as flip :: (a -> b -> c) -> (b -> a -> c) (.) :: (b -> c) -> (a -> b) -> a -> c -- usually be viewed as (.) :: (b -> c) -> (a -> b) -> (a -> c) -- aka. function composition map :: (a -> b) -> [a] -> [b] -- sometimes be viewed as map :: (a -> b) -> ([a] -> [b]) Haskell – Partial Application

• When defining a function, we can actually define it partially • But all definition of the same function must have the same number of parameters (when you are doing pattern matching) • The following three definition is exactly the same add1 x y = x + y add2 x = (+) x add3 = (+) Haskell – Partial Application

• Suppose now you want to define a function sumSquare to calculate the sum of all the elements’ square in a list

• The following one works perfectly sumSquare = sum . map (^ 2) -- sum :: (Flodable t, Num a) => t a -> a -- (^), map, (.) are all applied partially Haskell – Partial Application

• Challenge: • Define sortDesc which sort the element in descending order in one line. • It should have the signature sortDesc :: Ord a => [a] -> [a] Haskell – Area 2

• This time, let’s define a function to calculate the area of a circle

• For example, if I define it like this (let areaCirc r = pi * r^2):

• What will be the type of areaCirc? Haskell – Area 2

• Why? • Because (*) must take two parameter with the same type • And • Also the input and output of (^) need to have the same type • Therefore the compiler deduced that areaCirc must also take some Floating a Haskell – Area 2

• What if we pass an value with type Int into areaCirc ?

• Oh, error • How to solve this? Haskell – Area 2

• In this case, an explicit type conversion is required • fromIntegral is the function which can change an integral value to any kind of number formIntegral :: (Integral a, Num b) => a -> b

• This time it works! Haskell – Strict Type

• Unlike C++, Haskell is very strict on the variable type • E.g. you cannot multiply an Int with a Double

• Although the code is longer, this can assure that the programmer will not accidentally mixed up two types and helps preventing bugs Haskell – Strict Type

• As a result, some mathematic operators may look different from the one in C++ • There are two divisions, one for Fractional, one for Integral div :: Integral a => a -> a -> a (/) :: Fractional a => a -> a -> a • There are three different kinds of exponent (aka. pow) (^) :: (Integral b, Num a) => a -> b -> a (^^) :: (Fractional a, Integral b) => a -> b -> a (**) :: Floating a => a -> a -> a Haskell – Local Definition

• Now, let’s define a function to calculate the area of a triangle given the length of the three sides

• This can be calculated using the Heron’s fomula Haskell – Local Definition

• Let’s write this two lines area a b c = sqrt (s * (s - a) * (s - b) * (s - c)) s = (a + b + c) / 2 • And then load the file into ghci Haskell – Local Definition

• Oops

• What are abc in the definition of s ? Haskell – Local Definition

• We can use a where clause to make a local definition area a b c = sqrt (s * (s - a) * (s - b) * (s - c)) where s = (a + b + c) / 2

• Both the word where and local definition are indented 4 spaces to separate from the top level definitions Haskell – Local Definition

• Besides where clause, one can also use a let-in clause to do the same job area a b c = let s = (a + b + c) / 2 in sqrt (s * (s - a) * (s - b) * (s - c))

• Noted that the lines are indented by 4 spaces to separate from top- level definitions Haskell – if-then-else

• Suppose you want to define the factorial function, we may want to use the if-then-else statement • The syntax is like this factorial :: Integer -> Integer factorial x = if x == 0 then 1 else x * factorial (x - 1) • Unlike in C++, the else part is necessary • Otherwise the function may return nothing • Noted that the lines are indented by 4 spaces to separate from top-level definitions Haskell – case-of

• Suppose you want to define the fib function (fibonacci), we may want to use the case-of statement • The syntax is like this fib :: Integer -> Integer fib x = case x of 1 -> 1 2 -> 1 otherwise -> fib (x-1) + fib(x-2) • otherwise is similar to default in C++ • Noted that the lines are indented by 4 spaces to separate from top-level definitions Haskell – Guard

• Actually there is a more elegant way to define fib using guard • The syntax is like this: fib :: Integer -> Integer fib x | x <= 2 = 1 | otherwise = fib (x-1) + fib (x-2) • Noted that the two | are in the same column • Here, otherwise is the same as true • Does it looks like this? • Ps. There is an even elegant way to define fib using infinite list Haskell – Pattern Matching

• And there is also a more elegant way to define factorial using pattern matching • The syntax is like this: factorial :: Integer -> Integer factorial 0 = 1 factorial x = x * factorial (x-1) • When the function factorial is called, it will start to match the pattern from top of the file to bottom • It will use the first matched pattern as the definition • Can only match on concrete value or constructor • Runtime error occurs if nothing is matched Haskell – Pattern Matching

• We can use pattern matching to match the constructors data Contact = Phone Integer | Email String • You can define the following function: information (Phone n) = "Phone number is " ++ show n information (Email m) = "Email address is " ++ m • Producing the following result Haskell – Construction of List

• Four ways to generate a list using “..”

• [a..b]

--[1..5] == [1, 2, 3, 4, 5] --[1.5..5.5] == [1.5, 2.5, 3.5, 4.5, 5.5] --[1.5..5] == [1.5, 2.5, 3.5, 4.5] --['a'..'e'] == "abcde" Haskell – Construction of List

• Four ways to generate a list using “..”

• [a,b..c]

--[1, 3..10] == [1, 3, 5, 7, 9] --[1.5, 2..5] == [1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5] --[1.5, 2..3.75] == [1.5, 2, 2.5, 3, 3.5] --['a', ''..'z'] == "adgjmpsvy" Haskell – Construction of List

• Four ways to generate a list using “..” • [a..] (infinite list, don’t input this into ghci since it never ends)

--[1..] == [1, 2, 3, 4, 5, …] --[1.5..] == [1.5, 2.5, 3.5, 4.5, …]

• [a, b..] (infinite list, don’t input this into ghci since it never ends)

--[1, 3..] == [1, 3, 5, 7, 9, …] --[1.5, 2..] == [1.5, 2, 2.5, 3, …] Haskell – List Comprehension

• We can obtain a list from other lists • Syntax: [expression | predicate, predicate, …] • predicate can be a Bool or a statement in the form var <- list

• Example: --[x | x <- [1..20], x < 5] == [1, 2, 3, 4] --[2 * x | x <- [1..20], x < 5] == [2, 4, 6, 8] --[x | x <- [1..20], even x, x < 10] == [2, 4, 6, 8] --[(x, y) | x <- [0,1], y <- [0,1]] == [(0, 0), (0, 1), (1, 0), (1, 1)] Haskell – List

• We can build lists by concatenating two lists or insert an element into a list

[] :: [a] -- the empty list (:) :: a -> [a] -> [a] -- inserting new element at the beginning of a list (++) :: [a] -> [a] -> [a] -- concatenating two lists Haskell – List

--1:[] == [1] --1:2:3:[] == 1:2:[3] == 1:[2, 3] == [1, 2, 3] --[]:[] = [[]] --[] ++ [] == [] --[1] ++ [2] == [1, 2] --[1, 4] ++ [3, 2] == [1, 4, 3, 2] Haskell – Pattern Matching of Lists

• [] and (:) can be used in pattern matching but (++) cannot • the computer do not know where to cut the list

• Let’s implement a function myLength which returns the length of the input list

• First, the signature of myLength should be myLength :: [a] -> Int Haskell – Pattern Matching of Lists

• Then we should separate into two cases, the list is empty and non empty • When the list is empty mylength [] = 0 • When the list is non-empty myLength (_:as) = mylength as + 1 • Here “_” is a filler, it means that there is actually something but we don’t care what it is • It is strange but Notepad++ will highlight the word “as” Haskell – Pattern Matching of Lists

• So finally we have myLength :: [a] -> Int myLength [] = 0 myLength (_:as) = myLength as + 1 • Which is the same as myLength :: [a] -> Int myLength (_:as) = myLength as + 1 myLength _ = 0 • Noted that the order is revered, since we know that [] cannot match any (_:as) Haskell – Pattern Matching of Lists

• Challenge: • Can you define (++) :: [a] -> [a] -> [a] ? Haskell – Folds

• Have you realized that there are some kind of statement that appears in C++ and Python that is missing in Haskell? Haskell – Folds

• Loops! • E.g. for (int i = 0; i < n; i++) while (l < r) Haskell – Folds

• Without for loop, how can we do binary search? • ! (more precisely, recursive definition) binarySearch l r f | l+1 == r = l | f m = binarySearch l m f | otherwise = binarySearch m r f where m = (l + r) `div` 2

• Challenge: What is the type of binarySearch ? Haskell – Folds

• Without for loop, how can we find the sum of a list? • Recursion! (more precisely, recursive definition) sum [] = 0 sum (a:as) = a + sum as Haskell – Folds

• Without for loop, how can we find the product of a list? • Recursion! (more precisely, recursive definition) product [] = 1 product (a:as) = a * product as Haskell – Folds

• Don’t you think that finding the sum and the product are similar?

• Actually, there is a more elegant way to define sum and product using folds Haskell – Folds foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b -- foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...) foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b -- foldl f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn foldl1 :: Foldable t => (a -> a -> a) -> t a -> a -- foldl1 f a == foldl f (head a) $ tail a foldr1 :: Foldable t => (a -> a -> a) -> t a -> a -- foldl1 and foldr1 will throw exception if the input list is empty Haskell – Folds

• Fun fact: if you want to obtain a single value from a list, what you need should be one of the folds

sum = foldr (+) 0 product = foldr (*) 1 maximum = foldr1 max Haskell – Folds

• Challenge: • Can you define foldr for lists? • Can you define foldl for lists in terms of foldr? • Can you define the following functions in one line? reverse :: [a] -> [a] (++) :: [a] -> [a] -> [a] concat :: [[a]] -> [a] Haskell – Tuples

(,) :: a -> b -> (a, b) -- constructor of pair (,,) :: a -> b -> c -> (a, b, c) -- constructor of 3-tuple --… --Up to 62-tuple Haskell – Tuples Functions fst :: (a, b) -> a -- same as .first of pair in C++ snd :: (a, b) -> b -- same as .second of pair in C++ curry :: ((a, b) -> c) -> a -> b -> c -- can be viewed as ((a, b) -> c) -> (a -> b -> c) -- e.g. curry fst == const uncurry :: (a -> b -> c) -> (a, b) -> c -- can be viewed as (a -> b -> c) -> ((a, b) -> c) -- e.g. uncurry (+) (2, 3) == 5 Haskell – Tuples Functions zip :: [a] -> [b] -> [(a, b)] -- zip [10] [1, 2] == [(10, 1)] unzip :: [(a, b)] -> ([a], [b]) zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] -- zipWith (^) [10, 20, 30] [1, 2] == [10, 400] Haskell – Pattern Matching of Tuples

• A simple definition of fst and snd can be achieved using pattern matching: fst (x, y) = x snd (x, y) = y Haskell – Tuples

• Challenge: • Can you write a definition of zip in one line? • Can you define fst and snd using uncurry? Haskell – Challenges

• Define sortDesc which sort the element in descending order in one line. • It should have the signature sortDesc :: Ord a => [a] -> [a] • Can you define (++) :: [a] -> [a] -> [a]? • What is the type of binarySearch at slide 72? • Can you define foldr for lists? • Can you define foldl for lists in terms of foldr? • Can you define the following functions in one line? reverse :: [a] -> [a] (++) :: [a] -> [a] -> [a] concat :: [[a]] -> [a] Haskell – Challenges

• Can you write a definition of zip in one line? • Can you define fst and snd using uncurry? • Can you define subsequence :: [a] -> [[a]] which returns all the subsequence of a list? Haskell – Challenges

• Can you define an infinite list of square numbers in one line? • Can you define an infinite list of Fibonacci numbers in one line? • Can you define an infinite list of prime numbers? • Using and recursive definition • You can find one somewhere • Can you define an infinite list of Catalan numbers? Haskell – More

• You can read more on Wikibook • Search package and functions on Hoogle • Official website of Haskell Language Solution to Challenges • Some of the challenges are really challenging, it is normal if you can only solve some of them

• You may get more idea about functional programming by looking at the solution • Define sortDesc which sort the element in descending order in one line. • It should have the signature sortDesc :: Ord a => [a] -> [a] • Define sortDesc which sort the element in descending order in one line. • It should have the signature sortDesc :: Ord a => [a] -> [a]

sortDesc = sortBy $ flip compare Or sortDesc = reverse . sort • Can you define (++) :: [a] -> [a] -> [a]? • Can you define (++) :: [a] -> [a] -> [a]?

[] ++ b = b (a:as) ++ b = a : (as ++ b) • What is the type of binarySearch? binarySearch l r f | l+1 == r = l | f m = binarySearch l m f | otherwise = binarySearch m r f where m = (l + r) `div` 2 • What is the type of binarySearch? binarySearch l r f | l+1 == r = l | f m = binarySearch l m f | otherwise = binarySearch m r f where m = (l + r) `div` 2 binarySearch :: Integral a => a -> a -> (a -> Bool) -> a • Can you define foldr for lists? • Can you define foldr for lists? foldr f z [] = z foldr f z (a:as) = a `f` foldr f z as • Can you define foldl for lists in terms of foldr? • Can you define foldl for lists in terms of foldr? foldl f z = foldr (flip f) z . reverse • Can you define reverse :: [a] -> [a] in one line? • Can you define reverse :: [a] -> [a] in one line? reverse = foldl (flip (:)) [] • Can you define (++) :: [a] -> [a] -> [a] in one line? • Can you define (++) :: [a] -> [a] -> [a] in one line?

(++) = flip $ foldr (:) • Can you define concat :: [[a]] -> [a] in one line? • Can you define concat :: [[a]] -> [a] in one line? concat = foldr (++) [] -- more preferable Or concat = foldl (++) [] • Can you write a definition of zip in one line? • Can you write a definition of zip in one line? zip = zipWith (,) • Can you define fst and snd using uncurry? • Can you define fst and snd using uncurry? fst = uncurry const snd = uncurry $ flip const • Can you define subsequence :: [a] -> [[a]] which returns all the subsequence of a list? • Can you define subsequence :: [a] -> [[a]] which returns all the subsequence of a list? subsequence [] = [[]] subsequence (a:as) = map (a:) subseq ++ subseq where subseq = subsequence as • Can you define an infinite list of square numbers in one line? • Can you define an infinite list of square numbers in one line? squares = map (^2) [1..] • Can you define an infinite list of Fibonacci numbers in one line? • Can you define an infinite list of Fibonacci numbers in one line? fib = 1 : zipWith (+) (0:fib) fib • Can you define an infinite list of prime numbers? • Using Sieve of Eratosthenes and recursive definition • You can find one somewhere • Can you define an infinite list of prime numbers? • Using Sieve of Eratosthenes and recursive definition • You can find one somewhere primes = filterPrime [2..] where filterPrime (p:xs) = p : filterPrime [x | x <- xs, x `mod` p /= 0] • Can you define an infinite list of Catalan numbers? • Can you define an infinite list of Catalan numbers? catalan = map (fst.catalan') [1..] where catalan' 1 = (1, [1]) catalan' x = (res, res:ls) where res = sum $ zipWith (*) ls $ reverse ls (_, ls) = catalan' $ x-1