C ONSTRUCTING L ISTS R ECURSIVELY Compute all suffixes of a given string: suffixes :: String -> [String] For example, suffixes "Hello" ⇒ ["Hello", "ello", "llo", "lo", "o"] ➜ What is the base case? (What happens in case of an empty string?) ➜ How does the recursive step proceed? ✧ C ONSTRUCTING L ISTS R ECURSIVELY 1 Overall, we have suffixes :: String -> [String] suffixes "" = [] suffixes str = str : suffixes (tail str) ➜ We build the result list recursively using only [] and :. ➜ In fact, these two operators are enough to build any list. ➜ Usually, [] is called nil and : is called cons. C ONSTRUCTING L ISTS R ECURSIVELY 2 Overall, we have suffixes :: String -> [String] suffixes "" = [] suffixes str = str : suffixes (tail str) ➜ We build the result list recursively using only [] and :. ➜ In fact, these two operators are enough to build any list. ➜ Usually, [] is called nil and : is called cons. C ONSTRUCTING L ISTS R ECURSIVELY 2- A T HE TRUTH ABOUT L ISTS Haskell thinks of lists as being built from nil ([]) and cons (:): [x1 ,x2 ,x3 , . . . ,xn ] = x1 :(x2 :(x3 : · · · :(xn :[]))) ✧ Notice:: ➜ Repeated use of cons: recursive structure ➜ For each xi , there is one cons operator ➜ The list is terminated by nil ➜ The recursive representation is the original representation ➜ The closed notation (left hand side) is only a shorthand T HE TRUTH ABOUT L ISTS 3 T HE TRUTH ABOUT L ISTS Haskell thinks of lists as being built from nil ([]) and cons (:): [x1 ,x2 ,x3 , . . . ,xn ] = x1 :(x2 :(x3 : · · · :(xn :[]))) ✧ Notice:: ➜ Repeated use of cons: recursive structure ➜ For each xi , there is one cons operator ➜ The list is terminated by nil ➜ The recursive representation is the original representation ➜ The closed notation (left hand side) is only a shorthand T HE TRUTH ABOUT L ISTS 3- A PATTERN M ATCHING ON L ISTS We used pattern matching to decompose tuples: fst :: (a, b) -> a fst (x, y) = x fst ("Haskell", 7.1) ⇒ "Haskell" ➜ There is a symmetry between tuple construction and pattern matching. ➜ The same holds for lists: Using the elementary list constructors nil ([]) and cons (:), we can decompose lists in the same way as we build them. PATTERN M ATCHING ON L ISTS 4 PATTERN M ATCHING ON L ISTS We used pattern matching to decompose tuples: fst :: (a, b) -> a fst (x, y) = x fst ("Haskell", 7.1) ⇒ "Haskell" ➜ There is a symmetry between tuple construction and pattern matching. ➜ The same holds for lists: Using the elementary list constructors nil ([]) and cons (:), we can decompose lists in the same way as we build them. PATTERN M ATCHING ON L ISTS 4- A Extracting the head and tail via pattern matching: head :: [a] -> a head (x:xs) = x tail :: [a] -> [a] tail (x:xs) = xs The functions head and tail yield the two arguments to cons. ✧ For every non-empty lists xs, we have xs = head xs : tail xs Therefore, in an expression x:xs, we often call ➜ x the head of the resulting list and ➜ xs the tail of the resulting list. PATTERN M ATCHING ON L ISTS 5 Extracting the head and tail via pattern matching: head :: [a] -> a head (x:xs) = x tail :: [a] -> [a] tail (x:xs) = xs The functions head and tail yield the two arguments to cons. ✧ For every non-empty lists xs, we have xs = head xs : tail xs Therefore, in an expression x:xs, we often call ➜ x the head of the resulting list and ➜ xs the tail of the resulting list. PATTERN M ATCHING ON L ISTS 5- A Both head and tail are partial functions: ➜ There is no case covering nil ([]). For a total function, we have to provide two cases: ➜ one for nil ([]) and ➜ one for cons (:). Check whether a given list is empty: null :: [a] -> Bool null [] = True null (x:xs) = False ✧ PATTERN M ATCHING ON L ISTS 6 Both head and tail are partial functions: ➜ There is no case covering nil ([]). For a total function, we have to provide two cases: ➜ one for nil ([]) and ➜ one for cons (:). Check whether a given list is empty: null :: [a] -> Bool null [] = True null (x:xs) = False ✧ PATTERN M ATCHING ON L ISTS 6- A Both head and tail are partial functions: ➜ There is no case covering nil ([]). For a total function, we have to provide two cases: ➜ one for nil ([]) and ➜ one for cons (:). Check whether a given list is empty: null :: [a] -> Bool null [] = True null (x:xs) = False ✧ PATTERN M ATCHING ON L ISTS 6- B L IST T RAVERSAL So, let’s get back to the function product [x1 , x2 , . . . , xn ] = x1 * x2 * · · · * xn How can we define this function? Considering the recursive nature of lists: product (x1 : (x2 : . . . : (xn : []))) = x1 * x2 * · · · * xn Bringing the right hand side in a corresponding form: product (x1 : (x2 : . . . : (xn : []))) = (x1 * (x2 * · · · * (xn * 1))) ✧ L IST T RAVERSAL 7 L IST T RAVERSAL So, let’s get back to the function product [x1 , x2 , . . . , xn ] = x1 * x2 * · · · * xn How can we define this function? Considering the recursive nature of lists: product (x1 : (x2 : . . . : (xn : []))) = x1 * x2 * · · · * xn Bringing the right hand side in a corresponding form: product (x1 : (x2 : . . . : (xn : []))) = (x1 * (x2 * · · · * (xn * 1))) ✧ L IST T RAVERSAL 7- A L IST T RAVERSAL So, let’s get back to the function product [x1 , x2 , . . . , xn ] = x1 * x2 * · · · * xn How can we define this function? Considering the recursive nature of lists: product (x1 : (x2 : . . . : (xn : []))) = x1 * x2 * · · · * xn Bringing the right hand side in a corresponding form: product (x1 : (x2 : . . . : (xn : []))) = (x1 * (x2 * · · · * (xn * 1))) ✧ L IST T RAVERSAL 7- B The complete definition: product :: [Int] -> Int product [] = 1 product (x:xs) = x * product xs Some oberservations: ➜ The definition clearly replaces occurences of cons (:) by * and the occurence of nil ([]) by 1. ➜ Functions mapping a list to an elementary value are called reductions. L IST T RAVERSAL 8 The complete definition: product :: [Int] -> Int product [] = 1 product (x:xs) = x * product xs Some oberservations: ➜ The definition clearly replaces occurences of cons (:) by * and the occurence of nil ([]) by 1. ➜ Functions mapping a list to an elementary value are called reductions. L IST T RAVERSAL 8- A M ORE L IST T RAVERSALS product :: [Int] -> Int product [] = 1 product (x:xs) = x * product xs How can we gain an understanding of how this works? By executing the program stepwise. Execution of product [3, 5, 6]: product (3:(5:(6:[]))) ⇒ 3 * product (5:(6:[])) ⇒ 3 * 5 * product (6:[]) ⇒ 3 * 5 * 6 * product [] ⇒ 3 * 5 * 6 * 1 ⇒ 90 M ORE L IST T RAVERSALS 9 M ORE L IST T RAVERSALS product :: [Int] -> Int product [] = 1 product (x:xs) = x * product xs How can we gain an understanding of how this works? By executing the program stepwise. Execution of product [3, 5, 6]: product (3:(5:(6:[]))) ⇒ 3 * product (5:(6:[])) ⇒ 3 * 5 * product (6:[]) ⇒ 3 * 5 * 6 * product [] ⇒ 3 * 5 * 6 * 1 ⇒ 90 M ORE L IST T RAVERSALS 9- A M ORE L IST T RAVERSALS product :: [Int] -> Int product [] = 1 product (x:xs) = x * product xs How can we gain an understanding of how this works? By executing the program stepwise. Execution of product [3, 5, 6]: product (3:(5:(6:[]))) ⇒ 3 * product (5:(6:[])) ⇒ 3 * 5 * product (6:[]) ⇒ 3 * 5 * 6 * product [] ⇒ 3 * 5 * 6 * 1 ⇒ 90 M ORE L IST T RAVERSALS 9- B M ORE L IST T RAVERSALS product :: [Int] -> Int product [] = 1 product (x:xs) = x * product xs How can we gain an understanding of how this works? By executing the program stepwise. Execution of product [3, 5, 6]: product (3:(5:(6:[]))) ⇒ 3 * product (5:(6:[])) ⇒ 3 * 5 * product (6:[]) ⇒ 3 * 5 * 6 * product [] ⇒ 3 * 5 * 6 * 1 ⇒ 90 M ORE L IST T RAVERSALS 9- C M ORE L IST T RAVERSALS product :: [Int] -> Int product [] = 1 product (x:xs) = x * product xs How can we gain an understanding of how this works? By executing the program stepwise. Execution of product [3, 5, 6]: product (3:(5:(6:[]))) ⇒ 3 * product (5:(6:[])) ⇒ 3 * 5 * product (6:[]) ⇒ 3 * 5 * 6 * product [] ⇒ 3 * 5 * 6 * 1 ⇒ 90 M ORE L IST T RAVERSALS 9- D M ORE L IST T RAVERSALS product :: [Int] -> Int product [] = 1 product (x:xs) = x * product xs How can we gain an understanding of how this works? By executing the program stepwise. Execution of product [3, 5, 6]: product (3:(5:(6:[]))) ⇒ 3 * product (5:(6:[])) ⇒ 3 * 5 * product (6:[]) ⇒ 3 * 5 * 6 * product [] ⇒ 3 * 5 * 6 * 1 ⇒ 90 M ORE L IST T RAVERSALS 9- E M ORE L IST T RAVERSALS product :: [Int] -> Int product [] = 1 product (x:xs) = x * product xs How can we gain an understanding of how this works? By executing the program stepwise. Execution of product [3, 5, 6]: product (3:(5:(6:[]))) ⇒ 3 * product (5:(6:[])) ⇒ 3 * 5 * product (6:[]) ⇒ 3 * 5 * 6 * product [] ⇒ 3 * 5 * 6 * 1 ⇒ 90 M ORE L IST T RAVERSALS 9- F Concatenating Sublists: ➜ Lists can be nested, e.g., [[5, 6, 2], [], [4, 2]] :: [[Int]] ➜ concat merges sublists into one list, e.g., concat [[5, 6, 2], [], [4, 2]] ⇒ [5, 6, 2, 4, 2] ➜ What would a suitable specification of concat be? concat [xs1 , xs2 , . . . , xsn ] = xs1 ++ xs2 ++ · · · ++ xsn ✧ Full definition: concat :: [[a]] -> [a] concat [] = [] concat (xs:xss) = xs ++ concat xss M ORE L IST T RAVERSALS 10 Concatenating Sublists: ➜ Lists can be nested, e.g., [[5, 6, 2], [], [4, 2]] :: [[Int]] ➜ concat merges sublists into one list, e.g., concat [[5, 6, 2], [], [4, 2]] ⇒ [5, 6, 2, 4, 2] ➜ What would a suitable specification of concat be? concat [xs1 , xs2 , . . . , xsn ] = xs1 ++ xs2 ++ · · · ++ xsn ✧ Full definition: concat :: [[a]] -> [a] concat [] = [] concat (xs:xss) = xs ++ concat xss M ORE L IST T RAVERSALS 10- A Concatenating Sublists: ➜ Lists can be nested, e.g., [[5, 6, 2], [], [4, 2]] :: [[Int]] ➜ concat merges sublists into one list, e.g., concat [[5, 6, 2], [], [4, 2]] ⇒ [5, 6, 2, 4, 2] ➜ What would a suitable specification of concat be? concat [xs1 , xs2 , . . . , xsn ] = xs1 ++ xs2 ++ · · · ++ xsn ✧ Full definition: concat :: [[a]] -> [a] concat [] = [] concat (xs:xss) = xs ++ concat xss M ORE L IST T RAVERSALS 10- B Concatenating Sublists: ➜ Lists can be nested, e.g., [[5, 6, 2], [], [4, 2]] :: [[Int]] ➜ concat merges sublists into one list, e.g., concat [[5, 6, 2], [], [4, 2]] ⇒ [5, 6, 2, 4, 2] ➜ What would a suitable specification of concat be? concat [xs1 , xs2 , . . . , xsn ] = xs1 ++ xs2 ++ · · · ++ xsn ✧ Full definition: concat :: [[a]] -> [a] concat [] = [] concat (xs:xss) = xs ++ concat xss M ORE L IST T RAVERSALS 10- C Concatenating Sublists: ➜ Lists can be nested, e.g., [[5, 6, 2], [], [4, 2]] :: [[Int]] ➜ concat merges sublists into one list, e.g., concat [[5, 6, 2], [], [4, 2]] ⇒ [5, 6, 2, 4, 2] ➜ What would a suitable specification of concat be? concat [xs1 , xs2 , . . . , xsn ] = xs1 ++ xs2 ++ · · · ++ xsn ✧ Full definition: concat :: [[a]] -> [a] concat [] = [] concat (xs:xss) = xs ++ concat xss M ORE L IST T RAVERSALS 10- D