# Functional Programming --- CS 135 // 2021-02-18 ## Administrivia - Let me know if you need more time for Lab 2b - Combined Lab3a and Lab3b together this week + Functions more as an assignment so we can do more in-class examples today and Tuesday - Lab 3 is individual lab rather than group - I generated new groups this week for in-class exercises and breakout sessions though # Questions ## ...about anything? # Functional Programming ## Functional Programming - Since functional programming avoids the use of side effects, we depend on the following features to get things done: + Recursion (for repetition) + Currying (partial application) + Higher-order functions (for avoiding coupling and code duplication) + Lambda expressions (anonymous functions) ## Currying - All functions in Haskell technically take **one** argument and return **one** result - Consider the following functions: ```haskell mult :: Integer -> Integer -> Integer mult x y = x * y multBy2 :: Integer -> Integer multBy2 = mult 2 ``` - `mult 2` has type `Integer -> Integer` and multiplies its argument by 2 ## Currying - We can do this with literally any function ```haskell lessThan2 :: Integer -> Bool lessThan2 = (<2) ``` ```haskell addBang :: String -> String addBang = (++ "!") ``` - Given a function like the following: ```haskell f :: Integer -> Integer -> Integer -> Integer f x y z = x + y + z ``` What is the type of `f 5`? ## Higher-Order Functions - A **higher-order procedure** is a function that either: + Takes a function as an argument + Returns a function as a result - What are some higher-order functions that we've seen so far? ## Higher-Order Functions - `map :: (a -> b) -> [a] -> [b]` + Applies a function to each element of a list + `map (+1) [1, 2, 3]` - `filter :: (a -> Bool) -> [a] -> [a]` + Returns only the elements of a list that satisfy the given predicate + `filter even [0..10]` ## Higher-Order Functions - `(.)::(b -> c) -> (a -> b) -> a -> c` + Composes two functions together + `(f . g) x = f (g x)` + $(f\circ g)(x) = f(g(x))$ ```haskell timesThreePlusOne :: Integer -> Integer timesThreePlus1 = (+1) . (*3) ``` ## Lambda Expressions - Sometimes it is convenient to create an **anonymous function** using a **lambda expression** ```haskell filter (\x -> even x || x == 1) [0..10] ``` - Here, `\x -> even x || x == 1` defines a function (with no name) that is equivalent to: ```haskell f :: (Num a) => a -> Bool f x = even x || x == 1 ``` ## Lambda Expressions - We can also use multiple parameters in a lambda + `\x y -> (x * y) + 1` + This is a function that takes two parameters, multiplies them, then adds 1 ## List Pattern Matching - Recall that lists in Haskell are **linked lists** - We've primarily been using literals like `[1,2,3]` to build lists - Another way is with the **cons** operator: + `(:) :: a -> [a] -> [a]` + Adds an element to the beginning of the list + `5:[1,2,3]` is the same as `[5,1,2,3]` ## List Pattern Matching - You'll often see recursive functions over lists defined using pattern matching like the following: ```haskell sum :: [Integer] -> Integer sum [] = 0 sum (x:xs) = x + sum xs ``` - Here `(x:xs)` matches any **non-empty list** where `x` is the first element of the list and `xs` is the rest # Self Checks ## Check 1 - What's the type of this function? ```haskell both p q x = p x && q x ``` ```haskell a -> Bool -> a -> Bool -> a -> Bool -- 1 (a -> Bool) -> (a -> Bool) -> a -> Bool -- 2 (a -> Bool) -> (b -> Bool) -> c -> Bool -- 3 ``` ## Check 2 - What's the type of this function? ```haskell applyInOut f g x = f (g (f x)) ``` ```haskell (a -> b) -> (b -> a) -> a -> b -- 1 (a -> b) -> (b -> c) -> a -> c -- 2 (a -> a) -> (a -> a) -> a -> a -- 3 ``` ## Check 3 - Which one of the following functions adds its first argument to the second? ```haskell f x x = x + x -- 1 f x = \y -> x + y -- 2 f = \x y -> x + x -- 3 ``` ## Check 4 - Which one of these functions does not satisfy
`f 1 ==> 1`? ```haskell f x = (\y -> y) x -- 1 f x = \y -> y -- 2 f x = (\y -> x) x -- 3 ``` ## Check 5 - Which one of these functions is correctly typed? ```haskell f x y = not x; f :: (Bool -> Bool) -> Bool -- 1 f x = x ++ "a"; f :: Char -> String -- 2 f x = 'a' : x; f :: String -> String -- 3 ``` ## Check 6 - How many arguments does `drop 2` take? ## Check 7 - What does this function do? ```haskell f (_:x:_) = x ``` --- 1. Returns the first element of a list 2. Returns an arbitrary element of a list 3. Returns all except the first and last elements of a list 4. Returns the second element of a list ## Check 8 - What is the result of the following expression? ```haskell reverse $ take 5 . tail $ "This is a test"` ``` --- 1. `"i sih"` 2. `"set a"` 3. A type error ## Check 9 - If `f :: a -> b`, then what is the type of
`map (.f)`? ```haskell [b -> c] -> [a -> c] -- 1 [c -> a] -> [c -> b] -- 2 (b -> c) -> [a -> c] -- 3 [a] -> [b] -- 4 ``` ## Check 10 - What is the type of the leftmost `id` in `id id`? --- 1. unspecified 2. `a` 3. `a -> a` 4. `(a -> a) -> (a -> a)` ## Check 11 - What is the type of `const const`? --- 1. unspecified 2. `(c -> a -> b) -> a` 3. `c -> (a -> b -> a)` 4. `a -> b -> c -> a` # Exercises ## Exercise 1 - Define a function that checks if the given list is in increasing order ```haskell sorted :: [Int] -> Bool ``` ## Exercise 2 - Define the function `map` from scratch using lists and pattern matching. ```haskell map :: (a -> b) -> [a] -> [b] ``` ## Exercise 3 - Define a version of map that takes a two-argument function and two lists - For example: ```haskell map2 f [x,y,z,w] [a,b,c] -- ==> [f x a, f y b, f z c] ``` - If the lists have differing lengths, ignore the trailing elements of the longer list. ```haskell map2 :: (a -> b -> c) -> [a] -> [b] -> [c] ``` # Pattern Matching on an Expression