diff --git a/slides/sources/common/beamer.template b/slides/sources/common/beamer.template
index 710cd1304d2245fcdbc073e57485cd14aa95f2d0..9d13111c2089612bbb0de27d0d5acd6ebc7effe4 100644
--- a/slides/sources/common/beamer.template
+++ b/slides/sources/common/beamer.template
@@ -131,6 +131,7 @@ $endif$
 
 \renewcommand{\example}{\mbox{\boldred{Example}}}
 \newcommand{\question}{\mbox{\boldred{Question}}}
+\newcommand{\answer}{\mbox{\boldred{Answer}}}
 \renewcommand{\note}{\mbox{\red{Note:}}}
 
 % commas and semicolons
diff --git a/slides/sources/progfun1-1-7.md b/slides/sources/progfun1-1-7.md
index 0476effd36c73077dd4f73b58c4fb8c026b43c6f..abe6e53b09d37f80603b5604de46099372786634 100644
--- a/slides/sources/progfun1-1-7.md
+++ b/slides/sources/progfun1-1-7.md
@@ -120,6 +120,8 @@ In Scala, only directly recursive calls to the current function are optimized.
 
 One can require that a function is tail-recursive using a `@tailrec` annotation:
 
+      import scala.annotation.tailrec
+
       @tailrec
       def gcd(a: Int, b: Int): Int = ...
 
diff --git a/slides/sources/progfun1-2-2.md b/slides/sources/progfun1-2-2.md
index deaecf2427ea27b95202cb4379ee7d7b291d642c..bc8c457d6f24ef24d56924bc340d6f2c3290731f 100644
--- a/slides/sources/progfun1-2-2.md
+++ b/slides/sources/progfun1-2-2.md
@@ -10,7 +10,7 @@ Look again at the summation functions:
       def sumCubes(a: Int, b: Int)      = sum(x => x * x * x, a, b)
       def sumFactorials(a: Int, b: Int) = sum(fact, a, b)
 
-\question
+\red{Q:}
 
 Note that `a` and `b` get passed unchanged from `sumInts` and `sumCubes` into `sum`.
 
diff --git a/slides/sources/progfun1-4-1.md b/slides/sources/progfun1-4-1.md
index 5d43c24cb6049999ebb2a783a723b70f32788ab5..77cd10af293ab69f87313f7314e6d253736969cf 100644
--- a/slides/sources/progfun1-4-1.md
+++ b/slides/sources/progfun1-4-1.md
@@ -123,7 +123,7 @@ Here's a formulation of the `eval` method using type tests and casts:
           else if e.isInstanceOf[Sum] then
             eval(e.asInstanceOf[Sum].leftOp)
             + eval(e.asInstanceOf[Sum].rightOp)
-          else throw new Error("Unknown expression " + e)
+          else throw Error("Unknown expression " + e)
 
 Assessment of this solution:
 ->
diff --git a/slides/sources/progfun1-4-6.md b/slides/sources/progfun1-4-6.md
index 94c943c885268ffadd66f68365dcc515f0d92765..ed80394919185538be8be8d2c42ee9d0b93d73db 100644
--- a/slides/sources/progfun1-4-6.md
+++ b/slides/sources/progfun1-4-6.md
@@ -200,7 +200,7 @@ Lower Bounds
 
 But `prepend` is a natural method to have on immutable lists!
 
-\question: How can we make it variance-correct?
+\red{Q}: How can we make it variance-correct?
 \medskip
 
 ->
diff --git a/slides/sources/progfun1-5-0.md b/slides/sources/progfun1-5-0.md
deleted file mode 100644
index cfbae553b31dd3b870ad3393f18865c06812b612..0000000000000000000000000000000000000000
--- a/slides/sources/progfun1-5-0.md
+++ /dev/null
@@ -1,189 +0,0 @@
-% Lists
-%
-%
-Lists
-=====
-
-The list is a fundamental data structure in functional programming.
-
-A list having $\btt x_1, ..., x_n$
-as elements is written `List(`$\btt x_1, ..., x_n$`)`
-
-\example
-
-      val fruit  = List("apples", "oranges", "pears")
-      val nums   = List(1, 2, 3, 4)
-      val diag3  = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))
-      val empty  = List()
-
-There are two important differences between lists and arrays.
-
- - Lists are immutable --- the elements of a list cannot be changed.
- - Lists are recursive, while arrays are flat.
-
-Lists
-=====
-
-      val fruit  = List("apples", "oranges", "pears")
-      val diag3  = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))
-
-The List Type
-=============
-
-Like arrays, lists are \red{\em homogeneous}: the elements of a
-list must all have the same type.
-
-The type of a list with elements of type `T` is written `scala.List[T]` or shorter just `List[T]`
-
-\example
-
-      val fruit: List[String]    = List("apples", "oranges", "pears")
-      val nums : List[Int]       = List(1, 2, 3, 4)
-      val diag3: List[List[Int]] = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))
-      val empty: List[Nothing]   = List()
-
-Constructors of Lists
-=====================
-
-All lists are constructed from:
-
- - the empty list `Nil`, and
- - the construction operation `::` (pronounced \emph{cons}): \newline
-`x :: xs` gives a new list with the first element `x`, followed by the elements of `xs`.
-
-For example:
-
-      fruit = "apples" :: ("oranges" :: ("pears" :: Nil))
-      nums  = 1 :: (2 :: (3 :: (4 :: Nil)))
-      empty = Nil
-
-
-Right Associativity
-===================
-
-Convention: Operators ending in "`:`" associate to the right.
-
-\gap `A :: B :: C` is interpreted as `A :: (B :: C)`.
-
-We can thus omit the parentheses in the definition above.
-
-\example
-
-      val nums = 1 :: 2 :: 3 :: 4 :: Nil
-
-Operators ending in "`:`" are also different in the they are seen as method calls of the _right-hand_ operand.
-
-So the expression above is equivalent to
-
-      Nil.::(4).::(3).::(2).::(1)
-
-Operations on Lists
-===================
-
-All operations on lists can be expressed in terms of the following
-three operations:
-
-\begin{tabular}{ll}
-\verb`head`  &  the first element of the list \\
-\verb`tail`  &  the list composed of all the elements except the first. \\
-\verb`isEmpty` & `true` if the list is empty, `false` otherwise.
-\end{tabular}
-
-These operations are defined as methods of objects of type list.
-For example:
-
-      fruit.head      == "apples"
-      fruit.tail.head == "oranges"
-      diag3.head      == List(1, 0, 0)
-      empty.head      == throw new NoSuchElementException("head of empty list")
-
-List Patterns
-=============
-
-It is also possible to decompose lists with pattern matching.
-
-\begin{tabular}{lp{9cm}}
-      \verb`Nil`     &  The \verb`Nil` constant \\
-      \verb`p :: ps` &  A pattern that matches a list with a \verb`head` matching \verb`p` and a
-                        \verb`tail` matching \verb`ps`. \\
-      \verb`List(p1, ..., pn)` & same as \verb`p1 :: ... :: pn :: Nil`
-\end{tabular}
-
-\example
-
-\begin{tabular}{lp{9cm}}
-      \verb`1 :: 2 :: xs`       & Lists of that start with \verb`1` and then \verb`2`
-\\    \verb`x :: Nil`           & Lists of length 1
-\\    \verb`List(x)`            & Same as \verb`x :: Nil`
-\\    \verb`List()`             & The empty list, same as \verb`Nil`
-\\    \verb`List(2 :: xs)`      & A list that contains as only element another list
-                                  that starts with \verb`2`.
-\end{tabular}
-
-Exercise
-========
-
-Consider the pattern `x :: y :: List(xs, ys) :: zs`.
-
-What is the condition that describes most accurately the length `L`
-of the lists it matches?
-
-      O         L == 3
-      O         L == 4
-      O         L == 5
-      O         L >= 3
-      O         L >= 4
-      O         L >= 5
-->
-\quiz
-
-Sorting Lists
-=============
-
-Suppose we want to sort a list of numbers in ascending order:
-
- -  One way to sort the list `List(7, 3, 9, 2)` is to sort the
-  tail `List(3, 9, 2)` to obtain `List(2, 3, 9)`.
- -  The next step is to insert the head `7` in the right place
-  to obtain the result `List(2, 3, 7, 9)`.
-
-This idea describes \red{Insertion Sort} :
-
-      def isort(xs: List[Int]): List[Int] = xs match
-        case List() => List()
-        case y :: ys => insert(y, isort(ys))
-
-Exercise
-========
-
-Complete the definition insertion sort by filling in the `???`s in the definition below:
-
-      def insert(x: Int, xs: List[Int]): List[Int] = xs match
-        case List() => ???
-        case y :: ys => ???
-
-What is the worst-case complexity of insertion sort relative to the length of the input list `N`?
-
-      O      the sort takes constant time
-      O      proportional to N
-      O      proportional to N log(N)
-      O      proportional to N * N
-
-\quiz
-
-Exercise
-========
-
-Complete the definition insertion sort by filling in the `???`s in the definition below:
-
-      def insert(x: Int, xs: List[Int]): List[Int] = xs match
-        case List() =>
-        case y :: ys =>
-
-What is the worst-case complexity of insertion sort relative to the length of the input list `N`?
-
-      O      the sort takes constant time
-      O      proportional to N
-      O      proportional to N * log(N)
-      O      proportional to N * N
-
diff --git a/slides/sources/progfun1-5-1.md b/slides/sources/progfun1-5-1.md
index 7aa9b807ab6dd93ca08ac02b043481e89a665a3a..acdf3726dfca0950c20a45dad6db5fb9176a3981 100644
--- a/slides/sources/progfun1-5-1.md
+++ b/slides/sources/progfun1-5-1.md
@@ -1,220 +1,210 @@
-% More Functions on Lists
+% Lists
 %
 %
+Lists
+=====
 
-List Methods (1)
-================
+The list is a fundamental data structure in functional programming.
 
-\red{Sublists and element access:}
+A list having $\btt x_1, ..., x_n$
+as elements is written `List(`$\btt x_1, ..., x_n$`)`
 
-\begin{tabular}{lp{8cm}}
-   \verb`  xs.length     `  & The number of elements of \verb`xs`.
-\\ \verb`  xs.last`    & The list's last element, exception if \verb`xs` is empty.
-\\ \verb`  xs.init`    & A list consisting of all elements of \verb`xs` except the last one,
-                         exception if \verb`xs` is empty.
-\\ \verb`  xs take n` & A list consisting of the first \verb`n` elements of \verb`xs`, or \verb`xs` itself
-                         if it is shorter than \verb`n`.
-\\ \verb`  xs drop n` & The rest of the collection after taking \verb`n` elements.
-\\ \verb`  xs(n)`     & (or, written out, \verb`xs apply n`). The element of \verb`xs` at index \verb`n`.
+\example
 
-\end{tabular}
-
-List Methods (2)
-================
-
-\red{Creating new lists:}
-
-\begin{tabular}{lp{8cm}}
-   \verb`  xs ++ ys`        & The list consisting of all elements of \verb`xs`
-                              followed by all elements of \verb`ys`.
-\\ \verb`  xs.reverse`      & The list containing the elements of \verb`xs` in reversed order.
-\\ \verb`  xs updated (n, x)` & The list containing the same elements as \verb`xs`, except at index
-                            \verb`n` where it contains \verb`x`.
-\end{tabular}
+      val fruit  = List("apples", "oranges", "pears")
+      val nums   = List(1, 2, 3, 4)
+      val diag3  = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))
+      val empty  = List()
 
-\red{Finding elements:}
+There are two important differences between lists and arrays.
 
-\begin{tabular}{lp{8cm}}
-   \verb`  xs indexOf x `& The index of the first element in \verb`xs` equal to \verb`x`, or \verb`-1` if \verb`x`
-                          does not appear in \verb`xs`.
-\\ \verb`  xs contains x    ` & same as \verb`xs indexOf x >= 0`
-\end{tabular}
-
-Implementation of `last`
-========================
-
-The complexity of `head` is (small) constant time.
+ - Lists are immutable --- the elements of a list cannot be changed.
+ - Lists are recursive, while arrays are flat.
 
-What is the complexity of `last`?
+Lists
+=====
 
-To find out, let's write a possible implementation of `last` as a stand-alone function.
-
-      def last[T](xs: List[T]): T = xs match
-        case List() => throw new Error("last of empty list")
-        case List(x) =>
-        case y :: ys =>
+      val fruit  = List("apples", "oranges", "pears")
+      val diag3  = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))
 
-Implementation of `last`
-========================
+\vspace{2cm}
+$$
+\mbox{(Drawing on Blackboard)}
+$$
 
-The complexity of `head` is (small) constant time.
+The List Type
+=============
 
-What is the complexity of `last`?
+Like arrays, lists are \red{\em homogeneous}: the elements of a
+list must all have the same type.
 
-To find out, let's write a possible implementation of `last` as a stand-alone function.
+The type of a list with elements of type `T` is written `scala.List[T]` or shorter just `List[T]`
 
-      def last[T](xs: List[T]): T = xs match
-        case List() => throw new Error("last of empty list")
-        case List(x) => x
-        case y :: ys =>
-
-Implementation of `last`
-========================
-
-The complexity of `head` is (small) constant time.
-
-What is the complexity of `last`?
-
-To find out, let's write a possible implementation of `last` as a stand-alone function.
-
-      def last[T](xs: List[T]): T = xs match
-        case List() => throw new Error("last of empty list")
-        case List(x) => x
-        case y :: ys => last(ys)
-->
-So, `last` takes steps proportional to the length of the list `xs`.
-
-Exercise
-========
+\example
 
-Implement `init` as an external function, analogous to `last`.
+      val fruit: List[String]    = List("apples", "oranges", "pears")
+      val nums : List[Int]       = List(1, 2, 3, 4)
+      val diag3: List[List[Int]] = List(List(1, 0, 0), List(0, 1, 0), List(0, 0, 1))
+      val empty: List[Nothing]   = List()
 
-      def init[T](xs: List[T]): List[T] = xs match
-        case List() => throw new Error("init of empty list")
-        case List(x) => ???
-        case y :: ys => ???
+Constructors of Lists
+=====================
 
-\quiz
+All lists are constructed from:
 
-Exercise
-========
+ - the empty list `Nil`, and
+ - the construction operation `::` (pronounced \emph{cons}): \newline
+`x :: xs` gives a new list with the first element `x`, followed by the elements of `xs`.
 
-Implement `init` as an external function, analogous to `last`.
+For example:
 
-      def init[T](xs: List[T]): List[T] = xs match
-        case List() => throw new Error("init of empty list")
-        case List(x) =>
-        case y :: ys =>
+      fruit = "apples" :: ("oranges" :: ("pears" :: Nil))
+      nums  = 1 :: (2 :: (3 :: (4 :: Nil)))
+      empty = Nil
 
-\quiz
 
-Implementation of Concatenation
-===============================
+Right Associativity
+===================
 
-How can concatenation be implemented?
+Convention: Operators ending in "`:`" associate to the right.
 
-Let's try by writing a stand-alone function:
+\gap `A :: B :: C` is interpreted as `A :: (B :: C)`.
 
-      def concat[T](xs: List[T], ys: List[T]) =
+We can thus omit the parentheses in the definition above.
 
-Implementation of Concatenation
-===============================
+\example
 
-How can concatenation be implemented?
+      val nums = 1 :: 2 :: 3 :: 4 :: Nil
 
-Let's try by writing a stand-alone function:
+Operators ending in "`:`" are also different in the they are seen as method calls of the _right-hand_ operand.
 
-      def concat[T](xs: List[T], ys: List[T]) = xs match
-        case List() =>
-        case z :: zs =>
+So the expression above is equivalent to
 
-Implementation of Concatenation
-===============================
+      Nil.::(4).::(3).::(2).::(1)
 
-How can concatenation be implemented?
+Operations on Lists
+===================
 
-Let's try by writing a stand-alone function:
+All operations on lists can be expressed in terms of the following
+three operations:
 
-      def concat[T](xs: List[T], ys: List[T]) = xs match
-        case List() => ys
-        case z :: zs =>
+\begin{tabular}{ll}
+\verb`head`  &  the first element of the list \\
+\verb`tail`  &  the list composed of all the elements except the first. \\
+\verb`isEmpty` & `true` if the list is empty, `false` otherwise.
+\end{tabular}
 
-Implementation of Concatenation
-===============================
+These operations are defined as methods of objects of type list.
+For example:
 
-How can concatenation be implemented?
+      fruit.head      == "apples"
+      fruit.tail.head == "oranges"
+      diag3.head      == List(1, 0, 0)
+      empty.head      == throw NoSuchElementException("head of empty list")
 
-Let's try by writing a stand-alone function:
+List Patterns
+=============
 
-      def concat[T](xs: List[T], ys: List[T]) = xs match
-        case List() => ys
-        case z :: zs => z :: concat(zs, ys)
+It is also possible to decompose lists with pattern matching.
 
-->
-What is the complexity of `concat`?
+\begin{tabular}{lp{9cm}}
+      \verb`Nil`     &  The \verb`Nil` constant \\
+      \verb`p :: ps` &  A pattern that matches a list with a \verb`head` matching \verb`p` and a
+                        \verb`tail` matching \verb`ps`. \\
+      \verb`List(p1, ..., pn)` & same as \verb`p1 :: ... :: pn :: Nil`
+\end{tabular}
 
+\example
 
-Implementation of `reverse`
-===========================
+\begin{tabular}{lp{9cm}}
+      \verb`1 :: 2 :: xs`       & Lists of that start with \verb`1` and then \verb`2`
+\\    \verb`x :: Nil`           & Lists of length 1
+\\    \verb`List(x)`            & Same as \verb`x :: Nil`
+\\    \verb`List()`             & The empty list, same as \verb`Nil`
+\\    \verb`List(2 :: xs)`      & A list that contains as only element another list
+                                  that starts with \verb`2`.
+\end{tabular}
 
-How can reverse be implemented?
+Exercise
+========
 
-Let's try by writing a stand-alone function:
+Consider the pattern `x :: y :: List(xs, ys) :: zs`.
 
-     def reverse[T](xs: List[T]): List[T] = xs match
-       case List() =>
-       case y :: ys =>
+What is the condition that describes most accurately the length `L`
+of the lists it matches?
 
-Implementation of `reverse`
-===========================
+      O         L == 3
+      O         L == 4
+      O         L == 5
+      O         L >= 3
+      O         L >= 4
+      O         L >= 5
 
-How can reverse be implemented?
+\quiz
 
-Let's try by writing a stand-alone function:
+Exercise
+========
 
-     def reverse[T](xs: List[T]): List[T] = xs match
-       case List() => List()
-       case y :: ys =>
+Consider the pattern `x :: y :: List(xs, ys) :: zs`.
 
+What is the condition that describes most accurately the length `L`
+of the lists it matches?
 
+      O         L == 3
+      O         L == 4
+      O         L == 5
+      X         L >= 3
+      O         L >= 4
+      O         L >= 5
 
-Implementation of `reverse`
-===========================
+Sorting Lists
+=============
 
-How can reverse be implemented?
+Suppose we want to sort a list of numbers in ascending order:
 
-Let's try by writing a stand-alone function:
+ -  One way to sort the list `List(7, 3, 9, 2)` is to sort the
+  tail `List(3, 9, 2)` to obtain `List(2, 3, 9)`.
+ -  The next step is to insert the head `7` in the right place
+  to obtain the result `List(2, 3, 7, 9)`.
 
-     def reverse[T](xs: List[T]): List[T] = xs match
-       case List() => List()
-       case y :: ys => reverse(ys) ++ List(y)
-->
-What is the complexity of `reverse`?
+This idea describes \red{Insertion Sort} :
 
-\red{Can we do better?} (to be solved later).
+      def isort(xs: List[Int]): List[Int] = xs match
+        case List() => List()
+        case y :: ys => insert(y, isort(ys))
 
 Exercise
 ========
 
-Remove the `n`'th element of a list `xs`. If `n` is out of bounds, return `xs` itself.
+Complete the definition insertion sort by filling in the `???`s in the definition below:
 
-     def removeAt[T](n: Int, xs: List[T]) = ???
+      def insert(x: Int, xs: List[Int]): List[Int] = xs match
+        case List() => ???
+        case y :: ys => ???
 
-Usage example:
+What is the worst-case complexity of insertion sort relative to the length of the input list `N`?
 
-\begin{worksheet}
- \verb`removeAt(1, List('a', 'b', 'c', 'd'))` \wsf   List(a, c, d)
-\end{worksheet}
+      O      the sort takes constant time
+      O      proportional to N
+      O      proportional to N log(N)
+      O      proportional to N * N
 
-Exercise (Harder, Optional)
-===========================
+\quiz
 
-Flatten a list structure:
+Exercise
+========
 
-     def flatten(xs: List[Any]): List[Any] = ???
+Complete the definition insertion sort by filling in the `???`s in the definition below:
 
-     flatten(List(List(1, 1), 2, List(3, List(5, 8))))
-                 >   res0: List[Any] = List(1, 1, 2, 3, 5, 8)
+      def insert(x: Int, xs: List[Int]): List[Int] = xs match
+        case List() => List(x)
+        case y :: ys =>
+          if x < y then x :: xs else y :: insert(x, ys)
 
+What is the worst-case complexity of insertion sort relative to the length of the input list `N`?
 
+      O      the sort takes constant time
+      X      proportional to N
+      O      proportional to N * log(N)
+      O      proportional to N * N
 
diff --git a/slides/sources/progfun1-5-2.md b/slides/sources/progfun1-5-2.md
index fd3f940ae5ba0a159b6079f6508521c2d25a871d..a4269c6d18b8b24ede1cbae903b39fd4683bd455 100644
--- a/slides/sources/progfun1-5-2.md
+++ b/slides/sources/progfun1-5-2.md
@@ -1,97 +1,253 @@
-% Pairs and Tuples
+% More Functions on Lists
 %
 %
-Sorting Lists Faster
-====================
 
-As a non-trivial example, let's design a function to sort lists
-that is more efficient than insertion sort.
+List Methods (1)
+================
 
-A good algorithm for this is \red{merge sort}. The idea is as
-follows:
+\red{Sublists and element access:}
 
-If the list consists of zero or one elements, it is already sorted.
+\begin{tabular}{lp{8cm}}
+   \verb`  xs.length     `  & The number of elements of \verb`xs`.
+\\ \verb`  xs.last`    & The list's last element, exception if \verb`xs` is empty.
+\\ \verb`  xs.init`    & A list consisting of all elements of \verb`xs` except the last one,
+                         exception if \verb`xs` is empty.
+\\ \verb`  xs.take(n)` & A list consisting of the first \verb`n` elements of \verb`xs`, or \verb`xs` itself
+                         if it is shorter than \verb`n`.
+\\ \verb`  xs.drop(n)` & The rest of the collection after taking \verb`n` elements.
+\\ \verb`  xs(n)`      & (or, written out, \verb`xs.apply(n)`). The element of \verb`xs` at index \verb`n`.
 
-Otherwise,
+\end{tabular}
 
- - Separate the list into two sub-lists, each containing around half of
-the elements of the original list.
- - Sort the two sub-lists.
- - Merge the two sorted sub-lists into a single sorted list.
+List Methods (2)
+================
 
-First MergeSort Implementation
-==============================
+\red{Creating new lists:}
 
-Here is the implementation of that algorithm in Scala:
+\begin{tabular}{lp{8cm}}
+   \verb`  xs ++ ys`        & The list consisting of all elements of \verb`xs`
+                              followed by all elements of \verb`ys`.
+\\ \verb`  xs.reverse`      & The list containing the elements of \verb`xs` in reversed order.
+\\ \verb`  xs.updated(n, x)`& The list containing the same elements as \verb`xs`, except at index
+                              \verb`n` where it contains \verb`x`.
+\end{tabular}
 
-      def msort(xs: List[Int]): List[Int] =
-        val n = xs.length / 2
-        if n == 0 then xs
-        else
-          def merge(xs: List[Int], ys: List[Int]) = ???
-          val (fst, snd) = xs.splitAt(n)
-          merge(msort(fst), msort(snd))
+\red{Finding elements:}
 
-Definition of Merge
-===================
+\begin{tabular}{lp{8cm}}
+   \verb`  xs.indexOf(x)   `& The index of the first element in \verb`xs` equal to \verb`x`, or \verb`-1` if \verb`x`
+                              does not appear in \verb`xs`.
+\\ \verb`  xs.contains(x)  `& same as \verb`xs.indexOf(x) >= 0`
+\end{tabular}
 
-Here is a definition of the `merge` function:
+Implementation of `last`
+========================
 
-      def merge(xs: List[Int], ys: List[Int]) =
-        xs match
-          case Nil =>
-            ys
-          case x :: xs1
-            ys match
-              case Nil =>
-                xs
-              case y :: ys1 =>
-                if x < y then x :: merge(xs1, ys)
-                else y :: merge(xs, ys1)
-      end merge
+The complexity of `head` is (small) constant time.
 
-The SplitAt Function
-====================
+What is the complexity of `last`?
 
-The `splitAt` function on lists returns two sublists
+To find out, let's write a possible implementation of `last` as a stand-alone function.
 
- - the elements up the the given index
- - the elements from that index
+      def last[T](xs: List[T]): T = xs match
+        case List() => throw Error("last of empty list")
+        case List(x) =>
+        case y :: ys =>
 
-The lists are returned in a \red{pair}.
+Implementation of `last`
+========================
 
+The complexity of `head` is (small) constant time.
 
-Detour: Pair and Tuples
-=======================
+What is the complexity of `last`?
 
-The pair consisting of `x` and `y` is written `(x, y)` in Scala.
+To find out, let's write a possible implementation of `last` as a stand-alone function.
 
-\example
+      def last[T](xs: List[T]): T = xs match
+        case List() => throw Error("last of empty list")
+        case List(x) => x
+        case y :: ys =>
 
-\begin{worksheet}
-\verb`  val pair = ("answer", 42)` \wsf pair  : (String, Int) = (answer,42)
-\end{worksheet}
+Implementation of `last`
+========================
 
-The type of `pair` above is `(String, Int)`.
+The complexity of `head` is (small) constant time.
 
-Pairs can also be used as patterns:
+What is the complexity of `last`?
 
-\begin{worksheet}
-\verb`  val (label, value) = pair` \wsf  label  : String = answer \\
-                                 \wsn  value  : Int = 42
-\end{worksheet}
+To find out, let's write a possible implementation of `last` as a stand-alone function.
+
+      def last[T](xs: List[T]): T = xs match
+        case List() => throw Error("last of empty list")
+        case List(x) => x
+        case y :: ys => last(ys)
+->
+So, `last` takes steps proportional to the length of the list `xs`.
+
+Exercise
+========
+
+Implement `init` as an external function, analogous to `last`.
+
+      def init[T](xs: List[T]): List[T] = xs match
+        case List() => throw Error("init of empty list")
+        case List(x) => ???
+        case y :: ys => ???
+
+\quiz
+
+Exercise
+========
+
+Implement `init` as an external function, analogous to `last`.
+
+      def init[T](xs: List[T]): List[T] = xs match
+        case List() => throw Error("init of empty list")
+        case List(x) =>
+        case y :: ys =>
+
+\quiz
+
+Exercise
+========
+
+Implement `init` as an external function, analogous to `last`.
+
+      def init[T](xs: List[T]): List[T] = xs match
+        case List() => throw Error("init of empty list")
+        case List(x) => List()
+        case y :: ys =>
 
-This works analogously for tuples with more than two elements.
+\quiz
 
 Exercise
 ========
 
-The `merge` function as given uses a nested pattern match.
+Implement `init` as an external function, analogous to `last`.
+
+      def init[T](xs: List[T]): List[T] = xs match
+        case List() => throw Error("init of empty list")
+        case List(x) => List()
+        case y :: ys => y :: init(ys)
+
+\quiz
+
+Implementation of Concatenation
+===============================
+
+How can concatenation be implemented?
+
+Let's try by writing a stand-alone function:
+
+      def concat[T](xs: List[T], ys: List[T]) =
+
+Implementation of Concatenation
+===============================
+
+How can concatenation be implemented?
+
+Let's try by writing a stand-alone function:
+
+      def concat[T](xs: List[T], ys: List[T]) = xs match
+        case List() =>
+        case z :: zs =>
+
+Implementation of Concatenation
+===============================
+
+How can concatenation be implemented?
+
+Let's try by writing a stand-alone function:
+
+      def concat[T](xs: List[T], ys: List[T]) = xs match
+        case List() => ys
+        case z :: zs =>
+
+Implementation of Concatenation
+===============================
+
+How can concatenation be implemented?
+
+Let's try by writing a stand-alone function:
+
+      def concat[T](xs: List[T], ys: List[T]) = xs match
+        case List() => ys
+        case z :: zs => z :: concat(zs, ys)
+
+->
+
+What is the complexity of `concat`?
+
+->
+
+Answer: `O(xs.length)`
+
+Implementation of `reverse`
+===========================
+
+How can reverse be implemented?
+
+Let's try by writing a stand-alone function:
+
+     def reverse[T](xs: List[T]): List[T] = xs match
+       case List() =>
+       case y :: ys =>
+
+Implementation of `reverse`
+===========================
+
+How can reverse be implemented?
+
+Let's try by writing a stand-alone function:
+
+     def reverse[T](xs: List[T]): List[T] = xs match
+       case List() => List()
+       case y :: ys =>
+
+
+Implementation of `reverse`
+===========================
+
+How can reverse be implemented?
+
+Let's try by writing a stand-alone function:
+
+     def reverse[T](xs: List[T]): List[T] = xs match
+       case List() => List()
+       case y :: ys => reverse(ys) ++ List(y)
+
+->
+
+What is the complexity of `reverse`?
+
+->
+
+Answer: `O(xs.length * xs.length)`
+
+\red{Can we do better?} (to be solved later).
+
+Exercise
+========
+
+Remove the `n`'th element of a list `xs`. If `n` is out of bounds, return `xs` itself.
+
+     def removeAt[T](n: Int, xs: List[T]) = ???
+
+Usage example:
+
+\begin{worksheet}
+ \verb`removeAt(1, List('a', 'b', 'c', 'd'))` \wsf   List(a, c, d)
+\end{worksheet}
+
+Exercise (Harder, Optional)
+===========================
+
+Flatten a list structure:
+
+     def flatten(xs: List[Any]): List[Any] = ???
+
+     flatten(List(List(1, 1), 2, List(3, List(5, 8))))
+                 >   res0: List[Any] = List(1, 1, 2, 3, 5, 8)
 
-This does not reflect the inherent symmetry of the merge algorithm.
 
-Rewrite `merge` using a pattern matching over pairs.
 
-      def merge(xs: List[Int], ys: List[Int]): List[Int] =
-        (xs, ys) match
-          ???
diff --git a/slides/sources/progfun1-5-3.md b/slides/sources/progfun1-5-3.md
index cc8a125bba512f3e82b45cbcacebbd262ceb7953..23156bcd155ede968d92752ea14b33ce7d64c528 100644
--- a/slides/sources/progfun1-5-3.md
+++ b/slides/sources/progfun1-5-3.md
@@ -1,150 +1,168 @@
-% Implicit Parameters
+% Tuples and Generic Methods
 %
 %
+Sorting Lists Faster
+====================
 
-Making Sort more General
-========================
-
-Problem: How to parameterize `msort` so that it can also be used for
-lists with elements other than `Int`?
-
-      def msort[T](xs: List[T]): List[T] = ...
-
-does not work, because the comparison `<` in `merge` is not defined
-for arbitrary types `T`.
-
-\red{Idea:} Parameterize `merge` with the necessary comparison function.
-
-Parameterization of Sort
-========================
-
-The most flexible design is to make the function \verb@sort@
-polymorphic and to pass the comparison operation as an additional
-parameter:
-
-      def msort[T](xs: List[T])(lt: (T, T) => Boolean) =
-        ...
-          merge(msort(fst)(lt), msort(snd)(lt))
-
-Merge then needs to be adapted as follows:
-
-      def merge(xs: List[T], ys: List[T]) = (xs, ys) match
-        ...
-        case (x :: xs1, y :: ys1) =>
-          if lt(x, y) then ...
-          else ...
-
-Calling Parameterized Sort
-==========================
-
-We can now call `msort` as follows:
-
-      val xs = List(-5, 6, 3, 2, 7)
-      val fruits = List("apple", "pear", "orange", "pineapple")
+As a non-trivial example, let's design a function to sort lists
+that is more efficient than insertion sort.
 
-      msort(xs)((x: Int, y: Int) => x < y)
-      msort(fruits)((x: String, y: String) => x.compareTo(y) < 0)
+A good algorithm for this is \red{merge sort}. The idea is as
+follows:
 
-Or, since parameter types can be inferred from the call `msort(xs)`:
+If the list consists of zero or one elements, it is already sorted.
 
-      msort(xs)((x, y) => x < y)
+Otherwise,
 
+ - Separate the list into two sub-lists, each containing around half of
+the elements of the original list.
+ - Sort the two sub-lists.
+ - Merge the two sorted sub-lists into a single sorted list.
 
-Parametrization with Ordering
-=============================
+First MergeSort Implementation
+==============================
 
-There is already a class in the standard library that represents orderings.
+Here is the implementation of that algorithm in Scala:
 
-      scala.math.Ordering[T]
+      def msort(xs: List[Int]): List[Int] =
+        val n = xs.length / 2
+        if n == 0 then xs
+        else
+          def merge(xs: List[Int], ys: List[Int]) = ???
+          val (fst, snd) = xs.splitAt(n)
+          merge(msort(fst), msort(snd))
 
-provides ways to compare elements of type `T`. So instead of
-parameterizing with the `lt` operation directly, we could parameterize
-with `Ordering` instead:
+The SplitAt Function
+====================
 
-      def msort[T](xs: List[T])(ord: Ordering[T]) =
+The `splitAt` function on lists returns two sublists
 
-        def merge(xs: List[T], ys: List[T]) =
-          ... if ord.lt(x, y) then ...
+ - the elements up the the given index
+ - the elements from that index
 
-        ... merge(msort(fst)(ord), msort(snd)(ord)) ...
+The lists are returned in a \red{pair}.
 
-Ordering Instances:
-===================
 
-Calling the new `msort` can be done like this:
+Detour: Pair and Tuples
+=======================
 
-      import math.Ordering
+The pair consisting of `x` and `y` is written `(x, y)` in Scala.
 
-      msort(nums)(Ordering.Int)
-      msort(fruits)(Ordering.String)
+\example
 
-This makes use of the values `Int` and `String` defined in the
-`scala.math.Ordering` object, which produce the right orderings on
-integers and strings.
+\begin{worksheet}
+\verb`  val pair = ("answer", 42)` \wsf pair  : (String, Int) = (answer,42)
+\end{worksheet}
 
-Aside: Implicit Parameters
-==========================
+The type of `pair` above is `(String, Int)`.
 
-\red{Problem:} Passing around `lt` or `ord` values is cumbersome.
+Pairs can also be used as patterns:
 
-We can avoid this by making `ord` an implicit parameter.
+\begin{worksheet}
+\verb`  val (label, value) = pair` \wsf  label  : String = answer \\
+                                 \wsn  value  : Int = 42
+\end{worksheet}
 
-      def msort[T](xs: List[T])(implicit ord: Ordering[T]) =
+This works analogously for tuples with more than two elements.
 
-        def merge(xs: List[T], ys: List[T]) =
-          ... if ord.lt(x, y) then ...
+Translation of Tuples
+=====================
 
-        ... merge(msort(fst), msort(snd)) ...
+For small `(*)` $n$, the tuple type $\btt (T_1, ..., T_n)$ is an abbreviation of the
+parameterized type
+$$\btt
+  scala.Tuple{\it n}[T_1, ..., T_n]
+$$
+A tuple expression $\btt (e_1, ..., e_n)$
+is equivalent to the function application
+$$\btt
+   scala.Tuple{\it n}(e_1, ..., e_n)
+$$
+A tuple pattern $\btt (p_1, ..., p_n)$
+is equivalent to the constructor pattern
+$$\btt
+   scala.Tuple{\it n}(p_1, ..., p_n)
+$$
+`(*)` Currently, "small" = up to 22. There's also a TupleXXL class that handles Tuples larger than that limit.
 
-Then calls to `msort` can avoid the ordering parameters:
+The Tuple class
+===============
 
-      msort(nums)
-      msort(fruits)
+Here, all `Tuple`\mbox{\it n} classes are modeled after the following pattern:
 
-The compiler will figure out the right implicit to pass based on the
-demanded type.
+      case class Tuple2[T1, T2](_1: +T1, _2: +T2) {
+        override def toString = "(" + _1 + "," + _2 +")"
+      }
 
-Rules for Implicit Parameters
-=============================
+The fields of a tuple can be accessed with names `_1`, `_2`, ...
 
-Say, a function takes an implicit parameter of type `T`.
+So instead of the pattern binding
 
-The compiler will search an implicit definition that
+      val (label, value) = pair
 
- - is marked `implicit`
- - has a type compatible with `T`
- - is visible at the point of the function call, or is defined
-   in a companion object associated with `T`.
+one could also have written:
 
-If there is a single (most specific) definition, it will be taken as
-actual argument for the implicit parameter.
+      val label = pair._1
+      val value = pair._2
 
-Otherwise it's an error.
+But the pattern matching form is generally preferred.
 
-Exercise: Implicit Parameters
-=============================
+Definition of Merge
+===================
 
-Consider the following line of the definition of `msort`:
+Here is a definition of the `merge` function:
 
-        ... merge(msort(fst), msort(snd)) ...
+      def merge(xs: List[Int], ys: List[Int]) = (xs, ys) match
+        case (Nil, ys) => ys
+        case (xs, Nil) => xs
+        case (x :: xs1, y :: ys1) =>
+          if x < y then x :: merge(xs1, ys)
+          else y :: merge(xs, ys1)
 
-Which implicit argument is inserted?
+Making Sort more General
+========================
 
-      O        Ordering.Int
-      O        Ordering.String
-      O        the "ord" parameter of "msort"
+Problem: How to parameterize `msort` so that it can also be used for
+lists with elements other than `Int`?
 
+      def msort[T](xs: List[T]): List[T] = ???
 
+does not work, because the comparison `<` in `merge` is not defined
+for arbitrary types `T`.
 
+\red{Idea:} Parameterize `merge` with the necessary comparison function.
 
+Parameterization of Sort
+========================
 
+The most flexible design is to make the function \verb@sort@
+polymorphic and to pass the comparison operation as an additional
+parameter:
 
+      def msort[T](xs: List[T])(lt: (T, T) => Boolean) =
+        ...
+          merge(msort(fst)(lt), msort(snd)(lt))
 
+Merge then needs to be adapted as follows:
 
+      def merge(xs: List[T], ys: List[T]) = (xs, ys) match
+        ...
+        case (x :: xs1, y :: ys1) =>
+          if lt(x, y) then ...
+          else ...
 
+Calling Parameterized Sort
+==========================
 
+We can now call `msort` as follows:
 
+      val xs = List(-5, 6, 3, 2, 7)
+      val fruits = List("apple", "pear", "orange", "pineapple")
 
+      msort(xs)((x: Int, y: Int) => x < y)
+      msort(fruits)((x: String, y: String) => x.compareTo(y) < 0)
 
+Or, since parameter types can be inferred from the call `msort(xs)`:
 
+      msort(xs)((x, y) => x < y)
 
diff --git a/slides/sources/progfun1-5-4.md b/slides/sources/progfun1-5-4.md
index 66b09f59680c471497fe9028f972bae112217a44..b910554c803dacd39ca86de51b760845e38fe261 100644
--- a/slides/sources/progfun1-5-4.md
+++ b/slides/sources/progfun1-5-4.md
@@ -30,15 +30,15 @@ For example, to multiply each element of a list by the same factor, you could wr
         case Nil     => xs
         case y :: ys => y * factor :: scaleList(ys, factor)
 
-
-Map
-===
+Mapping
+=======
 
 
 This scheme can be generalized to the method `map` of the
 `List` class. A simple way to define `map` is as follows:
 
-      abstract class List[T] { ...
+      abstract class List[T]
+
         def map[U](f: T => U): List[U] = this match
           case Nil     => this
           case x :: xs => f(x) :: xs.map(f)
@@ -50,7 +50,7 @@ collections, not just lists).
 Using `map`, `scaleList` can be written more concisely.
 
       def scaleList(xs: List[Double], factor: Double) =
-        xs map (x => x * factor)
+        xs.map(x => x * factor)
 
 Exercise
 ========
@@ -62,6 +62,7 @@ return the result. Complete the two following equivalent definitions of
 
       def squareList(xs: List[Int]): List[Int] = xs match
         case Nil     => ???
+        case y :: ys => ???
 
       def squareList(xs: List[Int]): List[Int] =
         xs.map(???)
@@ -75,11 +76,11 @@ return the result. Complete the two following equivalent definitions of
 
 
       def squareList(xs: List[Int]): List[Int] = xs match
-        case Nil     =>
-        case y :: ys =>
+        case Nil     => Nil
+        case y :: ys => y * y :: squareList(ys)
 
       def squareList(xs: List[Int]): List[Int] =
-        xs.map
+        xs.map(x => x * x)
 
 Filtering
 =========
@@ -97,7 +98,7 @@ Filter
 This pattern is generalized by the method `filter` of the `List` class:
 
       abstract class List[T]
-        ...
+
         def filter(p: T => Boolean): List[T] = this match
           case Nil     => this
           case x :: xs => if p(x) then x :: xs.filter(p) else xs.filter(p)
@@ -106,7 +107,7 @@ This pattern is generalized by the method `filter` of the `List` class:
 Using `filter`, `posElems` can be written more concisely.
 
       def posElems(xs: List[Int]): List[Int] =
-        xs filter (x => x > 0)
+        xs.filter(x => x > 0)
 
 Variations of Filter
 ====================
@@ -115,11 +116,11 @@ Besides filter, there are also the following methods that extract
 sublists based on a predicate:
 
 \begin{tabular}{lp{8cm}}
-   \verb`  xs.filterNot(p)`  & Same as \verb`xs filter (x => !p(x))`; The list consisting of those elements of \verb`xs` that do not satisfy the predicate \verb`p`.
-\\ \verb`  xs.partition(p)`  & Same as \verb`(xs filter p, xs filterNot p)`, but computed in a single traversal of the list \verb`xs`.
+   \verb`  xs.filterNot(p)`  & Same as \verb`xs.filter(x => !p(x))`; The list consisting of those elements of \verb`xs` that do not satisfy the predicate \verb`p`.
+\\ \verb`  xs.partition(p)`  & Same as \verb`(xs.filter(p), xs.filterNot(p))`, but computed in a single traversal of the list \verb`xs`.
 \\ \verb`  xs.takeWhile(p)`  & The longest prefix of list \verb`xs` consisting of elements that all satisfy the predicate \verb`p`.
 \\ \verb`  xs.dropWhile(p)`  & The remainder of the list \verb`xs` after any leading elements satisfying \verb`p` have been removed.
-\\ \verb`  xs.span(p)`       & Same as \verb`(xs takeWhile p, xs dropWhile p)` but computed in a single traversal of the list \verb`xs`.
+\\ \verb`  xs.span(p)`       & Same as \verb`(xs.takeWhile(p), xs.dropWhile(p))` but computed in a single traversal of the list \verb`xs`.
 \end{tabular}
 
 Exercise
@@ -142,6 +143,25 @@ You can use the following template:
 Exercise
 ========
 
+Write a function `pack` that packs consecutive duplicates of list elements into sublists. For instance,
+
+      pack(List("a", "a", "a", "b", "c", "c", "a"))
+
+should give
+
+      List(List("a", "a", "a"), List("b"), List("c", "c"), List("a")).
+
+You can use the following template:
+
+      def pack[T](xs: List[T]): List[List[T]] = xs match
+        case Nil      => Nil
+        case x :: xs1 =>
+          val (more, rest) = xs1.partition(y => y == x)
+          (x :: more, pack(rest))
+
+Exercise
+========
+
 Using `pack`, write a function `encode` that produces the run-length
 encoding of a list.
 
@@ -153,3 +173,12 @@ should give
 
       List(("a", 3), ("b", 1), ("c", 2), ("a", 1)).
 
+Exercise
+========
+
+Using `pack`, write a function `encode` that produces the run-length
+encoding of a list.
+
+      def encode[T](xs: List[T]): List[(T, Int)] =
+        pack(xs).map(ys => (ys.head, ys.length))
+
diff --git a/slides/sources/progfun1-5-5.md b/slides/sources/progfun1-5-5.md
index 0eb95a95bb203dff416989e98e5f19e8b1fcfb55..8c802832d1a3f4d499cf504509a89773d7ff200f 100644
--- a/slides/sources/progfun1-5-5.md
+++ b/slides/sources/progfun1-5-5.md
@@ -17,6 +17,7 @@ We can implement this with the usual recursive schema:
         case Nil     => 0
         case y :: ys => y + sum(ys)
 
+
 ReduceLeft
 ==========
 
@@ -25,13 +26,12 @@ This pattern can be abstracted out using the generic method `reduceLeft`:
 `reduceLeft` inserts a given binary operator between adjacent elements
 of a list:
 
-      List(x1, ..., xn) reduceLeft op   =  (...(x1 op x2) op ... ) op xn
+      List(x1, ..., xn).reduceLeft(op)   =  x1.op(x2). ... .op(xn)
 
-\vspace{2cm}
 Using `reduceLeft`, we can simplify:
 
-      def sum(xs: List[Int])     = (0 :: xs) reduceLeft ((x, y) => x + y)
-      def product(xs: List[Int]) = (1 :: xs) reduceLeft ((x, y) => x * y)
+      def sum(xs: List[Int])     = (0 :: xs).reduceLeft((x, y) => x + y)
+      def product(xs: List[Int]) = (1 :: xs).reduceLeft((x, y) => x * y)
 
 A Shorter Way to Write Functions
 ================================
@@ -46,8 +46,8 @@ The parameters are defined at the next outer pair of parentheses (or the whole e
 
 So, `sum` and `product` can also be expressed like this:
 
-      def sum(xs: List[Int])     = (0 :: xs) reduceLeft (_ + _)
-      def product(xs: List[Int]) = (1 :: xs) reduceLeft (_ * _)
+      def sum(xs: List[Int])     = (0 :: xs).reduceLeft(_ + _)
+      def product(xs: List[Int]) = (1 :: xs).reduceLeft(_ * _)
 
 FoldLeft
 ========
@@ -56,14 +56,17 @@ The function `reduceLeft` is defined in terms of a more general function, `foldL
 
 `foldLeft` is like `reduceLeft` but takes an \red{accumulator}, `z`, as an additional parameter, which is returned when `foldLeft` is called on an empty list.
 
-      (List(x1, ..., xn) foldLeft z)(op)   =  (...(z op x1) op ... ) op xn
+      List(x1, ..., xn).foldLeft(z)(op)   =  z.op(x1).op ... .op(xn)
 
-\vspace{1.7cm}
+\vspace{1cm}
+$$
+\mbox{(Drawing on Blackboard)}
+$$
 
 So, `sum` and `product` can also be defined as follows:
 
-      def sum(xs: List[Int])      = (xs foldLeft 0) (_ + _)
-      def product(xs: List[Int])  = (xs foldLeft 1) (_ * _)
+      def sum(xs: List[Int])      =  xs.foldLeft(0)(_ + _)
+      def product(xs: List[Int])  =  xs.foldLeft(1)(_ * _)
 
 Implementations of ReduceLeft and FoldLeft
 ==========================================
@@ -73,13 +76,12 @@ Implementations of ReduceLeft and FoldLeft
       abstract class List[T]
 
         def reduceLeft(op: (T, T) => T): T = this match
-          case Nil     => throw new Error("Nil.reduceLeft")
-          case x :: xs => (xs foldLeft x)(op)
+          case Nil     => throw Error("Nil.reduceLeft")
+          case x :: xs => xs.foldLeft(x)(op)
 
         def foldLeft[U](z: U)(op: (U, T) => U): U = this match
           case Nil     => z
-          case x :: xs => (xs foldLeft op(z, x))(op)
-
+          case x :: xs => xs.foldLeft(op(z, x))(op)
 
 FoldRight and ReduceRight
 =========================
@@ -89,8 +91,13 @@ Applications of `foldLeft` and `reduceLeft` unfold on trees that lean to the lef
 They have two dual functions, `foldRight` and `reduceRight`, which
 produce trees which lean to the right, i.e.,
 
-      List(x1, ..., x{n-1}, xn) reduceRight op = x1 op ( ... (x{n-1} op xn) ... )
-      (List(x1, ..., xn) foldRight acc)(op)    = x1 op ( ... (xn op acc) ... )
+      List(x1, ..., x{n-1}, xn).reduceRight(op) = x1.op(x2.op( ... x{n-1}.op(xn) ... ))
+      (List(x1, ..., xn).foldRight(z)(op)       = x1.op(x2.op( ... xn.op(z) ...))
+
+\vspace{1.5cm}
+$$
+\mbox{(Drawing on Blackboard)}
+$$
 
 Implementation of FoldRight and ReduceRight
 ===========================================
@@ -98,12 +105,12 @@ Implementation of FoldRight and ReduceRight
 They are defined as follows
 
       def reduceRight(op: (T, T) => T): T = this match
-        case Nil => throw new Error("Nil.reduceRight")
+        case Nil      => throw Error("Nil.reduceRight")
         case x :: Nil => x
-        case x :: xs => op(x, xs.reduceRight(op))
+        case x :: xs  => op(x, xs.reduceRight(op))
 
       def foldRight[](z: U)(op: (T, U) => U): U = this match
-        case Nil => z
+        case Nil     => z
         case x :: xs => op(x, xs.foldRight(z)(op))
 
 Difference between FoldLeft and FoldRight
@@ -119,7 +126,7 @@ Exercise
 Here is another formulation of `concat`:
 
       def concat[T](xs: List[T], ys: List[T]): List[T] =
-        xs.foldRight(ys) (_ :: _)
+        xs.foldRight(ys)(_ :: _)
 
 Here, it isn't possible to replace `foldRight` by `foldLeft`. Why?
 
@@ -127,6 +134,20 @@ Here, it isn't possible to replace `foldRight` by `foldLeft`. Why?
       O     The resulting function would not terminate
       O     The result would be reversed
 
+Exercise
+========
+
+Here is another formulation of `concat`:
+
+      def concat[T](xs: List[T], ys: List[T]): List[T] =
+        xs.foldRight(ys)(_ :: _)
+
+Here, it isn't possible to replace `foldRight` by `foldLeft`. Why?
+
+      X     The types would not work out
+      O     The resulting function would not terminate
+      O     The result would be reversed
+
 Back to Reversing Lists
 =======================
 
@@ -151,11 +172,11 @@ We know `reverse(Nil) == Nil`, so we can compute as follows:
 ->
       =   reverse(Nil)
 ->
-      =   (Nil foldLeft z?)(op)
+      =   Nil.foldLeft(z?)(op)
 ->
       =   z?
 
-Consequently, `z? = List()`
+Consequently, `z? = Nil`
 
 Deduction of Reverse (2)
 ========================
@@ -167,11 +188,11 @@ list after `Nil` into our equation for `reverse`:
 ->
        =   reverse(List(x))
 ->
-       =   (List(x) foldLeft Nil)(op?)
+       =   List(x).foldLeft(Nil)(op?)
 ->
        =   op?(Nil, x)
 
-Consequently, `op?(Nil, x) = List(x) = x :: List()`.
+Consequently, `op?(Nil, x) = List(x) = x :: Nil`.
 
 This suggests to take for `op?` the operator `::` but with its operands swapped.
 
@@ -181,12 +202,26 @@ Deduction of Reverse(3)
 We thus arrive at the following implementation of `reverse`.
 
       def reverse[a](xs: List[T]): List[T] =
-        (xs foldLeft List[T]())((xs, x) => x :: xs)
+        xs.foldLeft(List[T]())((xs, x) => x :: xs)
 
 Remark: the type parameter in `List[T]()` is necessary for type inference.
 
-\question: What is the complexity of this implementation of `reverse` ?
+\red{Q}: What is the complexity of this implementation of `reverse` ?
+
+->
 
+\red{A}: Linear in `xs`
+
+Exercise
+========
+
+Complete the following definitions of the basic functions `map` and `length` on lists, such that their implementation uses `foldRight`:
+
+      def mapFun[T, U](xs: List[T], f: T => U): List[U] =
+        xs.foldRight(List[U]())( ??? )
+
+      def lengthFun[T](xs: List[T]): Int =
+        xs.foldRight(0)( ??? )
 
 Exercise
 ========
@@ -194,8 +229,8 @@ Exercise
 Complete the following definitions of the basic functions `map` and `length` on lists, such that their implementation uses `foldRight`:
 
       def mapFun[T, U](xs: List[T], f: T => U): List[U] =
-        (xs foldRight List[U]())( ??? )
+        xs.foldRight(List[U]())((y, ys) => f(y) :: ys)
 
       def lengthFun[T](xs: List[T]): Int =
-        (xs foldRight 0)( ??? )
+        xs.foldRight(0)((y, n) => n + 1)
 
diff --git a/slides/sources/progfun1-5-7.md b/slides/sources/progfun1-5-7.md
index 68687b4d4cd1d13c89e9acbe2d74345c662cc7a7..7d7071fcc938999297b3fd978b8b8ff7b2e28d10 100644
--- a/slides/sources/progfun1-5-7.md
+++ b/slides/sources/progfun1-5-7.md
@@ -94,9 +94,9 @@ Prove the following distribution law for `map` over concatenation.
 
 For any lists `xs`, `ys`, function `f`:
 
-      (xs ++ ys) map f  =  (xs map f) ++ (ys map f)
+      (xs ++ ys).map(f)  =  xs.map(f) ++ ys.map(f)
 
 You will need the clauses of ++ as well as the following clauses for `map`:
 
-            Nil map f  =  Nil
-      (x :: xs) map f  =  f(x) :: (xs map f)
+            Nil.map(f)  =  Nil
+      (x :: xs).map(f)  =  f(x) :: xs.map(f)
diff --git a/slides/sources/progfun1-5-implicits.md b/slides/sources/progfun1-5-implicits.md
new file mode 100644
index 0000000000000000000000000000000000000000..75ef2532dfb3bea6e8d35ad1f5101370936208c8
--- /dev/null
+++ b/slides/sources/progfun1-5-implicits.md
@@ -0,0 +1,125 @@
+% Implicit Parameters
+%
+%
+<!-- to be integrated with the implicits chapter -->
+Parametrization with Ordering
+=============================
+
+There is already a class in the standard library that represents orderings.
+
+      scala.math.Ordering[T]
+
+provides ways to compare elements of type `T`. So instead of
+parameterizing with the `lt` operation directly, we could parameterize
+with `Ordering` instead:
+
+      def msort[T](xs: List[T])(ord: Ordering[T]) =
+
+        def merge(xs: List[T], ys: List[T]) =
+          ... if ord.lt(x, y) then ...
+
+        ... merge(msort(fst)(ord), msort(snd)(ord)) ...
+
+Ordering Instances:
+===================
+
+Calling the new `msort` can be done like this:
+
+      import math.Ordering
+
+      msort(nums)(Ordering.Int)
+      msort(fruits)(Ordering.String)
+
+This makes use of the values `Int` and `String` defined in the
+`scala.math.Ordering` object, which produce the right orderings on
+integers and strings.
+
+Aside: Implicit Parameters
+==========================
+
+Calling `msort` can be done like this:
+
+      import math.Ordering
+
+      msort(nums)(Ordering.Int)
+      msort(fruits)(Ordering.String)
+
+\red{Problem:} Passing around `lt` or `ord` values is cumbersome.
+
+Aside: Implicit Parameters
+==========================
+
+We can avoid this by making `ord` an _implicit parameter_.
+
+      def msort[T](xs: List[T])(given ord: Ordering[T]) =
+
+        def merge(xs: List[T], ys: List[T]) =
+          ... if ord.lt(x, y) then ...
+
+        ... merge(msort(fst), msort(snd)) ...
+
+Then calls to `msort` can avoid the ordering parameters:
+
+      msort(nums)
+      msort(fruits)
+
+The compiler will figure out the right `Ordering` instance to pass based on the
+demanded type.
+
+Rules for Implicit Parameters
+=============================
+
+Say, a function takes an implicit parameter of type `T`.
+
+The compiler will search a definition or parameter that
+
+ - is marked `given`
+ - has a type compatible with `T`
+ - is visible at the point of the function call, or is defined
+   in a companion object associated with `T`.
+
+If there is a single (most specific) definition, it will be taken as
+actual argument for the implicit parameter.
+
+Otherwise it's an error.
+
+Exercise: Implicit Parameters
+=============================
+
+Consider the following line of the definition of `msort`:
+
+        ... merge(msort(fst), msort(snd)) ...
+
+Which implicit argument is inserted?
+
+      O        Ordering.Int
+      O        Ordering.String
+      O        the "ord" parameter of "msort"
+
+
+Exercise: Implicit Parameters
+=============================
+
+Consider the following line of the definition of `msort`:
+
+        ... merge(msort(fst), msort(snd)) ...
+
+Which implicit argument is inserted?
+
+      O        Ordering.Int
+      O        Ordering.String
+      X        the "ord" parameter of "msort"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/slides/sources/progfun1-6-1.md b/slides/sources/progfun1-6-1.md
index 5e2eb4ab24bcb7d7b90f2ceea00f8fbd133e91c8..f0ce0d394c54ead60f772b55e7f61e1bdacfaf52 100644
--- a/slides/sources/progfun1-6-1.md
+++ b/slides/sources/progfun1-6-1.md
@@ -35,13 +35,19 @@ Instead of `x :: xs`, there is
 Collection Hierarchy
 ====================
 
-A common base class of `List` and `Vector` is `Seq`, the class of all _sequences_. 
-
-`Seq` itself is a subclass of `Iterable`. 
-
-
+A common base class of `List` and `Vector` is `Seq`, the class of all _sequences_.
 
+`Seq` itself is a subclass of `Iterable`.
 
+~~~
+                        Iterable
+                      /    |     \
+                     /     |      \
+      ............Seq     Set      Map
+      .          /   \
+      .         /     \
+    Array    List     Vector
+~~~
 
 Arrays and Strings
 ==================
@@ -52,10 +58,10 @@ implicitly be converted to sequences where needed.
 (They cannot be subclasses of `Seq` because they come from Java)
 
       val xs: Array[Int] = Array(1, 2, 3)
-      xs map (x => 2 * x)
+      xs.map(x => 2 * x)
 
       val ys: String = "Hello world!"
-      ys filter (_.isUpper)
+      ys.filter(_.isUpper)
 
 Ranges
 ======
@@ -74,22 +80,22 @@ determine step value):
       1 to 10 by 3
       6 to 1 by -2
 
-Ranges a represented as single objects with three fields: 
+A `Range` is represented as a single object with three fields:
 lower bound, upper bound, step value.
 
 Some more Sequence Operations:
 ==============================
 
 \begin{tabular}{lp{8.7cm}}
-   \verb`  xs exists p    `  & \verb`true` if there is an element \verb`x` of \verb`xs` such that \verb`p(x)` holds, \verb`false` otherwise.
-\\ \verb`  xs forall p    `  & \verb`true` if \verb`p(x)` holds for all elements \verb`x` of \verb`xs`, \verb`false` otherwise.
-\\ \verb`  xs zip ys      `  & A sequence of pairs drawn from corresponding elements of sequences \verb`xs` and \verb`ys`.
-\\ \verb`  xs.unzip       `  & Splits a sequence of pairs \verb`xs` into two sequences consisting of the first, respectively second halves of all pairs.
-\\ \verb`  xs.flatMap f   `  & Applies collection-valued function \verb`f` to all elements of \verb`xs` and concatenates the results
-\\ \verb`  xs.sum         `  & The sum of all elements of this numeric collection.
-\\ \verb`  xs.product     `  & The product of all elements of this numeric collection
-\\ \verb`  xs.max         `  & The maximum of all elements of this collection (an \verb`Ordering` must exist)
-\\ \verb`  xs.min         `  & The minimum of all elements of this collection
+   \verb`  xs.exists(p)    `  & \verb`true` if there is an element \verb`x` of \verb`xs` such that \verb`p(x)` holds, \verb`false` otherwise.
+\\ \verb`  xs.forall(p)    `  & \verb`true` if \verb`p(x)` holds for all elements \verb`x` of \verb`xs`, \verb`false` otherwise.
+\\ \verb`  xs.zip(ys)      `  & A sequence of pairs drawn from corresponding elements of sequences \verb`xs` and \verb`ys`.
+\\ \verb`  xs.unzip        `  & Splits a sequence of pairs \verb`xs` into two sequences consisting of the first, respectively second halves of all pairs.
+\\ \verb`  xs.flatMap(f)   `  & Applies collection-valued function \verb`f` to all elements of \verb`xs` and concatenates the results
+\\ \verb`  xs.sum          `  & The sum of all elements of this numeric collection.
+\\ \verb`  xs.product      `  & The product of all elements of this numeric collection
+\\ \verb`  xs.max          `  & The maximum of all elements of this collection (an \verb`Ordering` must exist)
+\\ \verb`  xs.min          `  & The minimum of all elements of this collection
 \end{tabular}
 
 Example: Combinations
@@ -97,14 +103,14 @@ Example: Combinations
 
 To list all combinations of numbers `x` and `y` where `x` is drawn from `1..M` and `y` is drawn from `1..N`:
 
-      (1 to M) flatMap (x => 
+      (1 to M).flatMap(x =>
 
 Example: Combinations
 =====================
 
 To list all combinations of numbers `x` and `y` where `x` is drawn from `1..M` and `y` is drawn from `1..N`:
 
-      (1 to M) flatMap (x => (1 to N) map (y => (x, y)))
+      (1 to M).flatMap(x => (1 to N).map(y => (x, y)))
 
 Example: Scalar Product
 =======================
@@ -112,21 +118,36 @@ Example: Scalar Product
 To compute the scalar product of two vectors:
 
       def scalarProduct(xs: Vector[Double], ys: Vector[Double]): Double =
-        (xs zip ys).map(xy => xy._1 * xy._2).sum
+        xs.zip(ys).map(xy => xy._1 * xy._2).sum
 ->
 An alternative way to write this is with a \red{pattern matching function value}.
 
       def scalarProduct(xs: Vector[Double], ys: Vector[Double]): Double =
-        (xs zip ys).map{ case (x, y) => x * y }.sum
+        xs.zip(ys).map { case (x, y) => x * y }.sum
 
 Generally, the function value
 
       { case p1 => e1 ... case pn => en }
 
-is equivalent to 
+is equivalent to
 
       x => x match { case p1 => e1 ... case pn => en }
 
+Example: Scalar Product
+=======================
+
+For simple tuple decomposition, the `case` prefix in the pattern can be omitted.
+
+So, the previous code can be simplified to:
+
+      def scalarProduct(xs: Vector[Double], ys: Vector[Double]): Double =
+        xs.zip(ys).map((x, y) => x * y).sum
+
+Or, even simpler
+
+      def scalarProduct(xs: Vector[Double], ys: Vector[Double]): Double =
+        xs.zip(ys).map(_ * _).sum
+
 Exercise:
 =========
 
@@ -146,7 +167,8 @@ A number `n` is \red{prime} if the only divisors of `n` are `1` and `n` itself.
 What is a high-level way to write a test for primality of numbers? For
 once, value conciseness over efficiency.
 
-      def isPrime(n: Int): Boolean = 
+      def isPrime(n: Int): Boolean =
+        (2 to srqt(n)).forall(d => n % d == 0)
 
 \quiz
 
diff --git a/slides/sources/progfun1-6-2.md b/slides/sources/progfun1-6-2.md
index 1c6c5482e92f00182ba90dd7fb41272dcbdc4cdf..ddc5e381d48ad86f182cba0e8ecc5aa4530016a9 100644
--- a/slides/sources/progfun1-6-2.md
+++ b/slides/sources/progfun1-6-2.md
@@ -32,8 +32,8 @@ One natural way to generate the sequence of pairs is to:
 
 This can be achieved by combining `until` and `map`:
 
-      (1 until n) map (i =>
-        (1 until i) map (j => (i, j)))
+      (1 until n).map(i =>
+        (1 until i).map(j => (i, j)))
 
 
 Generate Pairs
@@ -43,7 +43,7 @@ The previous step gave a sequence of sequences, let's call it `xss`.
 
 We can combine all the sub-sequences using `foldRight` with `++`:
 
-      (xss foldRight Seq[Int]())(_ ++ _)
+      xss.foldRight(Seq[Int]())(_ ++ _)
 
 Or, equivalently, we use the built-in method `flatten`
 
@@ -51,20 +51,20 @@ Or, equivalently, we use the built-in method `flatten`
 
 This gives:
 
-      ((1 until n) map (i =>
-        (1 until i) map (j => (i, j)))).flatten
+      ((1 until n).map(i =>
+        (1 until i)map(j => (i, j)))).flatten
 
 Generate Pairs (2)
 ==================
 
 Here's a useful law:
 
-     xs flatMap f  =  (xs map f).flatten
+     xs.flatMap(f)  =   xs.map(f).flatten
 
 Hence, the above expression can be simplified to
 
-    (1 until n) flatMap (i =>
-        (1 until i) map (j => (i, j)))
+    (1 until n).flatMap(i =>
+        (1 until i).map(j => (i, j)))
 
 
 Assembling the pieces
@@ -72,9 +72,9 @@ Assembling the pieces
 
 By reassembling the pieces, we obtain the following expression:
 
-    (1 until n) flatMap (i =>
-       (1 until i) map (j => (i, j))) filter ( pair =>
-          isPrime(pair._1 + pair._2))
+    (1 until n)
+      .flatMap(i => (1 until i).map(j => (i, j)))
+      .filter((x, y) => isPrime(x + y))
 
 This works, but makes most people's head hurt.
 
@@ -99,11 +99,14 @@ Let `persons` be a list of elements of class `Person`, with fields `name` and `a
 
 To obtain the names of persons over 20 years old, you can write:
 
-      for ( p <- persons if p.age > 20 ) yield p.name
+      for p <- persons if p.age > 20
+      yield p.name
 
 which is equivalent to:
 
-      persons filter (p => p.age > 20) map (p => p.name)
+      persons
+        .filter(p => p.age > 20)
+        .map(p => p.name)
 
 The for-expression is similar to loops in imperative languages, except
 that it builds a list of the results of all iterations.
@@ -113,7 +116,7 @@ Syntax of For
 
 A for-expression is of the form
 
-      for ( s ) yield e
+      for s yield e
 
 where `s` is a sequence of \red{generators} and \red{filters},
 and `e` is an expression whose value is returned by an iteration.
@@ -124,10 +127,6 @@ and `e` is an expression whose value is returned by an iteration.
 - The sequence must start with a generator.
 - If there are several generators in the sequence, the last generators vary faster than the first.
 
-Instead of `( s )`, braces `{ s }` can also be used, and then the
-sequence of generators and filters can be written on multiple lines
-without requiring semicolons.
-
 Use of For
 ==========
 
@@ -151,5 +150,5 @@ a `for`:
 
       def scalarProduct(xs: List[Double], ys: List[Double]) : Double =
 ->
-        (for ((x, y) <- xs zip ys) yield x * y).sum
+        (for ((x, y) <- xs.zip(ys)) yield x * y).sum
 \quiz
diff --git a/slides/sources/progfun1-6-3.md b/slides/sources/progfun1-6-3.md
index 826285276a86787614606223ab895a06f56db69d..d2352261df3ce2743d94c63834d5bb65521628ff 100644
--- a/slides/sources/progfun1-6-3.md
+++ b/slides/sources/progfun1-6-3.md
@@ -63,14 +63,13 @@ Implementation
 
       def queens(n: Int) =
         def placeQueens(k: Int): Set[List[Int]] =
-          if k == 0 Set(List())
+          if k == 0 then Set(List())
           else
             for
               queens <- placeQueens(k - 1)
               col <- 0 until n
               if isSafe(col, queens)
-            yield
-              col :: queens
+            yield col :: queens
         placeQueens(n)
 
 Exercise
@@ -85,3 +84,4 @@ which tests if a queen placed in an indicated column `col` is secure amongst the
 It is assumed that the new queen is placed in the next available row after the other placed queens (in other words: in row `queens.length`).
 
 \quiz
+
diff --git a/slides/sources/progfun1-6-4.md b/slides/sources/progfun1-6-4.md
index 2ee574be2a30d48ff4b64cb88aceecab751005c6..23759337472f0b22d370c6a5005413bd616fbcf2 100644
--- a/slides/sources/progfun1-6-4.md
+++ b/slides/sources/progfun1-6-4.md
@@ -23,7 +23,7 @@ Class `Map[Key, Value]` extends the collection type \newline
 Therefore, maps support the same collection operations as other iterables do. Example:
 
       val countryOfCapital = capitalOfCountry.map((x, y) => (y, x))
-                      // Map("Washington" -> "US", "Bern" -> "Switzerland")
+                            // Map("Washington" -> "US", "Bern" -> "Switzerland")
 
 Note that maps extend iterables of key/value _pairs_.
 
@@ -50,8 +50,8 @@ Applying a map to a non-existing key gives an error:
 
 To query a map without knowing beforehand whether it contains a given key, you can use the `get` operation:
 
-      capitalOfCountry get "US"      // Some("Washington")
-      capitalOfCountry get "Andorra" // None
+      capitalOfCountry.get("US")      // Some("Washington")
+      capitalOfCountry.get("Andorra") // None
 
 The result of a `get` operation is an `Option` value.
 
@@ -64,7 +64,7 @@ The `Option` type is defined as:
       case class Some[+A](value: A) extends Option[A]
       object None extends Option[Nothing]
 
-The expression `map get key` returns
+The expression `map.get(key)` returns
 
 - `None` \gap if `map` does not contain the given `key`,
 - `Some(x)` \ \ if `map` associates the given `key` with the value `x`.
@@ -86,6 +86,26 @@ Options also support quite a few operations of the other collections.
 
 I invite you to try them out!
 
+Updating Maps
+=============
+
+Functional updates of a map are done with the `+` and `++` operations:
+
+\begin{tabular}{lp{8cm}}
+   \verb`  m + (k -> v)`  & The map that takes key `k` to value `v` \\
+   \verb` `               & and is otherwise equal to `m`  \\
+   \verb`  m ++ kvs`      & The map `m` updated via `+` with all key/value pairs in `kvs`
+\end{tabular}
+
+These operations are purely functional. For instance,
+
+\begin{worksheet}
+val m1 = Map("red" -> 1, "blue" -> 2)  \wsf    m1 = Map(red -> 1, blue -> 2) \\
+val m2 = m1 + ("blue" -> 3)            \wsf    m2 = Map(red -> 1, blue -> 3) \\
+m1                                     \wsf    Map(red -> 1, blue -> 2)
+\end{worksheet}
+
+
 Sorted and GroupBy
 ==================
 
@@ -95,17 +115,19 @@ Two useful operation of SQL queries in addition to for-expressions are
 `orderBy` on a collection can be expressed by `sortWith` and `sorted`.
 
       val fruit = List("apple", "pear", "orange", "pineapple")
-      fruit sortWith (_.length < _.length)  // List("pear", "apple", "orange", "pineapple")
-      fruit.sorted      // List("apple", "orange", "pear", "pineapple")
+      fruit.sortWith(_.length < _.length)  // List("pear", "apple", "orange", "pineapple")
+      fruit.sorted                         // List("apple", "orange", "pear", "pineapple")
 
 `groupBy` is available on Scala collections. It partitions a collection
 into a map of collections according to a _discriminator function_ `f`.
 
 \example:
 
-      fruit groupBy (_.head)  //> Map(p -> List(pear, pineapple),
+      fruit.groupBy(_.head)   //> Map(p -> List(pear, pineapple),
                               //|     a -> List(apple),
                               //|     o -> List(orange))
+<!---
+
 Map Example
 ===========
 
@@ -127,7 +149,7 @@ in the map.
 There is an operation `withDefaultValue` that turns a map into a
 total function:
 
-      val cap1 = capitalOfCountry withDefaultValue "<unknown>"
+      val cap1 = capitalOfCountry.withDefaultValue("<unknown>")
       cap1("Andorra")             // "<unknown>"
 
 Variable Length Argument Lists
@@ -144,7 +166,7 @@ Problem: The number of `key -> value` pairs passed to `Map` can vary.
 We can accommodate this pattern using a \red{repeated parameter}:
 
        def Polynom(bindings: (Int, Double)*) =
-         new Polynom(bindings.toMap withDefaultValue 0)
+         Polynom(bindings.toMap.withDefaultValue(0))
 
        Polynom(1 -> 2.0, 3 -> 4.0, 5 -> 6.2)
 
@@ -154,31 +176,30 @@ Inside the `Polynom` function, `bindings` is seen as a
 Final Implementation of Polynom
 ===============================
 
-    class Poly(terms0: Map[Int, Double])
+    class Polynom(terms0: Map[Int, Double])
       def this(bindings: (Int, Double)*) = this(bindings.toMap)
 
-      val terms = terms0 withDefaultValue 0.0
-
-      def + (other: Poly) = new Poly(terms ++ (other.terms map adjust))
-
-      def adjust(term: (Int, Double)): (Int, Double) =
+      val terms = terms0.withDefaultValue(0.0)
+      def + (other: Polynom) = Polynom(terms ++ other.terms.map(adjust))
+      def adjust(term: (Int, Double)): (Int, Double) = {
         val (exp, coeff) = term
         exp -> (coeff + terms(exp))
+      }
 
-      override def toString =
-        val termStrings =
-          for (exp, coeff) <- terms.toList.sorted.reverse
-          yield s"${coeff}x^$exp"
-        termStrings.mkString(" + ")
+    override def toString =
+      val termStrings =
+        for (exp, coeff) <- terms.toList.sorted.reverse
+        yield s"${coeff}x^$exp"
+      termStrings.mkString(" + ")
 
 Exercise
 ========
 
-The `+` operation on `Poly` used map concatenation with `++`.
+The `+` operation on `Polynom` used map concatenation with `++`.
 Design another version of `+` in terms of `foldLeft`:
 
-    def + (other: Poly) =
-      new Poly((other.terms foldLeft ???)(addTerm)
+    def + (other: Polynom) =
+      Polynom(other.terms.foldLeft(???)(addTerm))
 
     def addTerm(terms: Map[Int, Double], term: (Int, Double)) =
       ???
@@ -192,3 +213,23 @@ Which of the two versions do you believe is more efficient?
 
 \quiz
 
+Exercise
+========
+
+The `+` operation on `Polynom` used map concatenation with `++`.
+Design another version of `+` in terms of `foldLeft`:
+
+    def + (other: Polynom) =
+      Polynom(other.terms.foldLeft(terms)(addTerm))
+
+    def addTerm(terms: Map[Int, Double], term: (Int, Double)) =
+      val (exp, coeff) = term
+      terms + (exp, coeff + terms(exp))
+
+Which of the two versions do you believe is more efficient?
+
+      O        The version using ++
+      X        The version using foldLeft
+
+->
+-->
diff --git a/slides/sources/progfun1-6-5.md b/slides/sources/progfun1-6-5.md
index 1b3d92a4eaba7af58d146cbc5b9153890151d54c..c8ba60f68b1f649eeb33a21053639fa2830957c6 100644
--- a/slides/sources/progfun1-6-5.md
+++ b/slides/sources/progfun1-6-5.md
@@ -7,38 +7,244 @@ Task
 Phone keys have mnemonics assigned to them.
 
       val mnemonics = Map(
-            '2' -> "ABC", '3' -> "DEF", '4' -> "GHI", '5' -> "JKL", 
+            '2' -> "ABC", '3' -> "DEF", '4' -> "GHI", '5' -> "JKL",
             '6' -> "MNO", '7' -> "PQRS", '8' -> "TUV", '9' -> "WXYZ")
 
-Assume you are given a dictionary `words` as a list of words. 
+Assume you are given a dictionary `words` as a list of words.
 
-Design a method `translate` such that
+Design a method `encode` such that
 
-       translate(phoneNumber)
+       encode(phoneNumber)
 
-produces all phrases of words 
+produces all phrases of words
 that can serve as mnemonics for the phone number.
 
 \example: The phone number "7225247386" should have the mnemonic
 `Scala is fun` as one element of the set of solution phrases.
 
+Outline
+=======
+
+~~~
+class Coder(words: List[String]) {
+  val mnemonics = Map(...)
+
+  /** Maps a letter to the digit it represents */
+  val charCode: Map[Char, Char] = ???
+
+  /** Maps a word to the digit string it can represent */
+  private def wordCode(word: String): String = ???
+
+  /** Maps a digit string to all words in the dictionary that represent it */
+  private val wordsForNum: Map[String, List[String]] = ???
+
+  /** All ways to encode a number as a list of words */
+  def encode(number: String): Set[List[String]] = ???
+}
+~~~
+
+Implementation (1)
+==================
+
+~~~
+class Coder(words: List[String]) {
+  val mnemonics = Map(...)
+
+  /** Maps a letter to the digit it represents */
+  val charCode: Map[Char, Char] =
+~~~
+
+Implementation (1)
+==================
+
+~~~
+class Coder(words: List[String]) {
+  val mnemonics = Map(...)
+
+  /** Maps a letter to the digit it represents */
+  val charCode: Map[Char, Char] =
+    for (digit, str) <- mnemonics; ltr <- str yield ltr -> digit
+~~~
+
+Implementation (1)
+==================
+
+~~~
+class Coder(words: List[String]) {
+  val mnemonics = Map(...)
+
+  /** Maps a letter to the digit it represents */
+  val charCode: Map[Char, Char] =
+    for (digit, str) <- mnemonics; ltr <- str yield ltr -> digit
+
+  /** Maps a word to the digit string it can represent */
+  private def wordCode(word: String): String =
+~~~
+
+Implementation (1)
+==================
+
+~~~
+class Coder(words: List[String]) {
+  val mnemonics = Map(...)
+
+  /** Maps a letter to the digit it represents */
+  val charCode: Map[Char, Char] =
+    for (digit, str) <- mnemonics; ltr <- str yield ltr -> digit
+
+  /** Maps a word to the digit string it can represent */
+  private def wordCode(word: String): String = word.toUpperCase.map(charCode)
+~~~
+
+Implementation (1)
+==================
+
+~~~
+class Coder(words: List[String]) {
+  val mnemonics = Map(...)
+
+  /** Maps a letter to the digit it represents */
+  val charCode: Map[Char, Char] =
+    for (digit, str) <- mnemonics; ltr <- str yield ltr -> digit
+
+  /** Maps a word to the digit string it can represent */
+  private def wordCode(word: String): String = word.toUpperCase.map(charCode)
+
+  /** Maps a digit string to all words in the dictionary that represent it */
+  private val wordsForNum: Map[String, List[String]] =
+~~~
+
+Implementation (1)
+==================
+
+~~~
+class Coder(words: List[String]) {
+  val mnemonics = Map(...)
+
+  /** Maps a letter to the digit it represents */
+  val charCode: Map[Char, Char] =
+    for (digit, str) <- mnemonics; ltr <- str yield ltr -> digit
+
+  /** Maps a word to the digit string it can represent */
+  private def wordCode(word: String): String = word.toUpperCase.map(charCode)
+
+  /** Maps a digit string to all words in the dictionary that represent it */
+  private val wordsForNum: Map[String, List[String]] =
+    words.groupBy(wordCode).withDefaultValue(Nil)
+~~~
+
+Implementation (2)
+==================
+
+~~~
+  /** All ways to encode a number as a list of words */
+  def encode(number: String): Set[List[String]] =
+~~~
+
+Idea: use divide and conquer
+
+Implementation (2)
+==================
+
+~~~
+  /** All ways to encode a number as a list of words */
+  def encode(number: String): Set[List[String]] =
+    if number.isEmpty then ???
+    else ???
+~~~
+
+Implementation (2)
+==================
+
+~~~
+  /** All ways to encode a number as a list of words */
+  def encode(number: String): Set[List[String]] =
+    if number.isEmpty then Set(Nil)
+    else ???
+~~~
+
+Implementation (2)
+==================
+
+~~~
+  /** All ways to encode a number as a list of words */
+  def encode(number: String): Set[List[String]] =
+    if number.isEmpty then Set(Nil)
+    else
+      for
+        splitPoint <- (1 to number.length).toSet
+        word <- ???
+        rest <- ???
+      yield word :: rest
+~~~
+
+Implementation (2)
+==================
+
+~~~
+  /** All ways to encode a number as a list of words */
+  def encode(number: String): Set[List[String]] =
+    if number.isEmpty then Set(Nil)
+    else
+      for
+        splitPoint <- (1 to number.length).toSet
+        word <- wordsForNum(number.take(splitPoint))
+        rest <- ???
+      yield word :: rest
+~~~
+
+Implementation (2)
+==================
+
+~~~
+  /** All ways to encode a number as a list of words */
+  def encode(number: String): Set[List[String]] =
+    if number.isEmpty then Set(Nil)
+    else
+      for
+        splitPoint <- (1 to number.length).toSet
+        word <- wordsForNum(number.take(splitPoint))
+        rest <- encode(number.drop(splitPoint))
+      yield word :: rest
+~~~
+
+Testing It
+==========
+
+A test program:
+
+~~~
+  @main def code(number: String) =
+    val coder = Coder(List(
+      "Scala", "Python", "Ruby", "C",
+      "rocks", "socks", "sucks", "works", "pack"))
+    coder.encode(number).map(_.mkString(" "))
+~~~
+
+A sample run:
+
+~~~
+> scala code "7225276257"
+HashSet(Scala rocks, pack C rocks, pack C socks, Scala socks)
+~~~
+
 Background
 ==========
 
 This example was taken from:
 \begin{quote}
-Lutz Prechelt: An Empirical Comparison of Seven Programming Languages. IEEE Computer 33(10): 23-29 (2000) 
+Lutz Prechelt: An Empirical Comparison of Seven Programming Languages. IEEE Computer 33(10): 23-29 (2000)
 \end{quote}
 
 Tested with Tcl, Python, Perl, Rexx, Java, C++, C.
 
-Code size medians: 
+Code size medians:
 
 - 100 loc  for scripting languages
 - 200-300 loc for the others
 
-The Future?
-===========
+Benefits
+========
 
 Scala's immutable collections are:
 
@@ -48,4 +254,4 @@ Scala's immutable collections are:
 - _fast_: collection ops are tuned, can be parallelized.
 - _universal_: one vocabulary to work on all kinds of collections.
 
-This makes them a very attractive tool for software development
+This makes them an attractive tool for software development
diff --git a/slides/sources/src/ListSpecification.scala b/slides/sources/src/ListSpecification.scala
index d2326987ddd62de2f192850dbf667f94604b155a..668a0d414adc49bc1c2207902ff260d1df93d852 100644
--- a/slides/sources/src/ListSpecification.scala
+++ b/slides/sources/src/ListSpecification.scala
@@ -8,15 +8,15 @@ object ListSpecification extends Properties("List") {
   property("double reverse") = forAll { (lst: List[Int]) =>
     lst.reverse.reverse == lst
   }
-  
+
 //  property("zip reverse") = forAll { (a: List[Int], b: List[Int]) =>
-//    (a.reverse zip b.reverse) == (a zip b).reverse
+//    a.reverse.zip(b.reverse) == a.zip(b).reverse
 //  }
-  
+
 //  property("zip reverse") = forAll { (a: List[Int], b: List[Int]) =>
 //    val a1 = a.take(b.length)
 //    val b1 = b.take(a.length)
-//    (a1.reverse zip b1.reverse) == (a1 zip b1).reverse
+//    a1.reverse.zip(b1.reverse) == a1.zip(b1).reverse
 //  }
 
 }
\ No newline at end of file
diff --git a/slides/sources/src/maps.sc b/slides/sources/src/maps.sc
index 40796e1a2588fbb44c0c4a58ac0b080d0befd4e8..e3de773f85d4d09a76b0e2bb58b96768f81bd711 100644
--- a/slides/sources/src/maps.sc
+++ b/slides/sources/src/maps.sc
@@ -2,7 +2,7 @@ package week6
 
 object maps {
   val romanNumerals = Map('I' -> 1, 'V' -> 5, 'X' -> 10)
-                                                  //> romanNumerals  : scala.collection.immutable.Map[Char,Int] = Map(I -> 1, V -> 
+                                                  //> romanNumerals  : scala.collection.immutable.Map[Char,Int] = Map(I -> 1, V ->
                                                   //| 5, X -> 10)
   val capitalOfCountry = Map("US" -> "Washington", "Switzerland" -> "Bern")
                                                   //> capitalOfCountry  : scala.collection.immutable.Map[String,String] = Map(US -
diff --git a/slides/sources/src/pairs.sc b/slides/sources/src/pairs.sc
index c6a9ef92bdea3cc1de52e33ab2793342dc84d9be..dce366c69866a1241c6d5ed1211f3c272a753210 100644
--- a/slides/sources/src/pairs.sc
+++ b/slides/sources/src/pairs.sc
@@ -3,12 +3,12 @@ package week6
 object pairs {
 
   val s = (1 to 6).toSet                          //> s  : scala.collection.immutable.Set[Int] = Set(5, 1, 6, 2, 3, 4)
-  
+
   s map (_ / 2)                                   //> res0: scala.collection.immutable.Set[Int] = Set(2, 0, 3, 1)
-  
+
   s contains 5                                    //> res1: Boolean = true
-  
-  def isPrime(n: Int) = (2 until n) forall (n % _ != 0)
+
+  def isPrime(n: Int) = (2 until n).forall(n % _ != 0)
                                                   //> isPrime: (n: Int)Boolean
   val n = 8                                       //> n  : Int = 8
   val sublists =
@@ -28,125 +28,120 @@ object pairs {
                                                   //| ), (4,1), (4,3), (5,2), (6,1), (6,5), (7,4), (7,6))
 
   def queens(n: Int) = {
-    def placeQueens(k: Int): Set[List[Int]] = {
+    def placeQueens(k: Int): Set[List[Int]] =
       if (k == 0) Set(List())
-      else {
-        def isSafe(col: Int, queens: List[Int]) = {
+      else
+        def isSafe(col: Int, queens: List[Int]) =
           val row = queens.length
-    		  queens zip (row - 1 to 0 by -1) forall {
-      		  case (c, r) => col != c && (row - r) != math.abs(col - c)
-    		  }
-    		}
-        for {
+          queens.zip(row - 1 to 0 by -1).forall(
+            (c, r) => col != c && (row - r) != math.abs(col - c))
+        for
           queens <- placeQueens(k - 1)
           col <- 0 until n
           if isSafe(col, queens)
-        } yield col :: queens
-      }
-    }
-    placeQueens(n)
-  }                                               //> queens: (n: Int)Set[List[Int]]
-  
+        yield col :: queens
+    placeQueens(n)                               //> queens: (n: Int)Set[List[Int]]
+
   def show(queens: List[Int]) = {
     val lines =
 	    for (col <- queens.reverse)
   	  yield Vector.fill(queens.length)("* ").updated(col, "X ").mkString
   	"\n" + (lines mkString "\n")
   }                                               //> show: (queens: List[Int])String
-    
+
   (queens(8) take 10 map show) mkString "\n"      //> res4: String = "
-                                                  //| * * * X * * * * 
-                                                  //| * * * * * * * X 
-                                                  //| X * * * * * * * 
-                                                  //| * * * * X * * * 
-                                                  //| * * * * * * X * 
-                                                  //| * X * * * * * * 
-                                                  //| * * * * * X * * 
-                                                  //| * * X * * * * * 
-                                                  //| 
-                                                  //| * * * * X * * * 
-                                                  //| * * X * * * * * 
-                                                  //| X * * * * * * * 
-                                                  //| * * * * * * X * 
-                                                  //| * X * * * * * * 
-                                                  //| * * * * * * * X 
-                                                  //| * * * * * X * * 
-                                                  //| * * * X * * * * 
-                                                  //| 
-                                                  //| * X * * * * * * 
-                                                  //| * * * * X * * * 
-                                                  //| * * * * * * X * 
-                                                  //| X * * * * * * * 
-                                                  //| * * X * * * * * 
-                                                  //| * * * * * * * X 
-                                                  //| * * * * * X * * 
-                                                  //| * * * X * * * * 
-                                                  //| 
-                                                  //| * * * * * * X * 
-                                                  //| * * * X * * * * 
-                                                  //| * X * * * * * * 
-                                                  //| * * * * * * * X 
-                                                  //| * * * * * X * * 
-                                                  //| X * * * * * * * 
-                                                  //| * * X * * * * * 
-                                                  //| * * * * X * * * 
-                                                  //| 
-                                                  //| * * * * * X * * 
-                                                  //| * * X * * * * * 
-                                                  //| * * * * * * X * 
-                                                  //| * X * * * * * * 
-                                                  //| * * * X * * * * 
-                                                  //| * * * * * * * X 
-                                                  //| X * * * * * * * 
-                                                  //| * * * * X * * * 
-                                                  //| 
-                                                  //| * * * * * X * * 
-                                                  //| * * X * * * * * 
-                                                  //| * * * * * * X * 
-                                                  //| * * * X * * * * 
-                                                  //| X * * * * * * * 
-                                                  //| * * * * * * * X 
-                                                  //| * X * * * * * * 
-                                                  //| * * * * X * * * 
-                                                  //| 
-                                                  //| * * * * * X * * 
-                                                  //| * * * X * * * * 
-                                                  //| X * * * * * * * 
-                                                  //| * * * * X * * * 
-                                                  //| * * * * * * * X 
-                                                  //| * X * * * * * * 
-                                                  //| * * * * * * X * 
-                                                  //| * * X * * * * * 
-                                                  //| 
-                                                  //| * * * * X * * * 
-                                                  //| * * * * * * X * 
-                                                  //| * X * * * * * * 
-                                                  //| * * * X * * * * 
-                                                  //| * * * * * * * X 
-                                                  //| X * * * * * * * 
-                                                  //| * * X * * * * * 
-                                                  //| * * * * * X * * 
-                                                  //| 
-                                                  //| * X * * * * * * 
-                                                  //| * * * * * X * * 
-                                                  //| X * * * * * * * 
-                                                  //| * * * * * * X * 
-                                                  //| * * * X * * * * 
-                                                  //| * * * * * * * X 
-                                                  //| * * X * * * * * 
-                                                  //| * * * * X * * * 
-                                                  //| 
-                                                  //| * * * * * X * * 
-                                                  //| * * * X * * * * 
-                                                  //| * X * * * * * * 
-                                                  //| * * * * * * * X 
-                                                  //| * * * * X * * * 
-                                                  //| * * * * * * X * 
-                                                  //| X * * * * * * * 
+                                                  //| * * * X * * * *
+                                                  //| * * * * * * * X
+                                                  //| X * * * * * * *
+                                                  //| * * * * X * * *
+                                                  //| * * * * * * X *
+                                                  //| * X * * * * * *
+                                                  //| * * * * * X * *
+                                                  //| * * X * * * * *
+                                                  //|
+                                                  //| * * * * X * * *
+                                                  //| * * X * * * * *
+                                                  //| X * * * * * * *
+                                                  //| * * * * * * X *
+                                                  //| * X * * * * * *
+                                                  //| * * * * * * * X
+                                                  //| * * * * * X * *
+                                                  //| * * * X * * * *
+                                                  //|
+                                                  //| * X * * * * * *
+                                                  //| * * * * X * * *
+                                                  //| * * * * * * X *
+                                                  //| X * * * * * * *
+                                                  //| * * X * * * * *
+                                                  //| * * * * * * * X
+                                                  //| * * * * * X * *
+                                                  //| * * * X * * * *
+                                                  //|
+                                                  //| * * * * * * X *
+                                                  //| * * * X * * * *
+                                                  //| * X * * * * * *
+                                                  //| * * * * * * * X
+                                                  //| * * * * * X * *
+                                                  //| X * * * * * * *
+                                                  //| * * X * * * * *
+                                                  //| * * * * X * * *
+                                                  //|
+                                                  //| * * * * * X * *
+                                                  //| * * X * * * * *
+                                                  //| * * * * * * X *
+                                                  //| * X * * * * * *
+                                                  //| * * * X * * * *
+                                                  //| * * * * * * * X
+                                                  //| X * * * * * * *
+                                                  //| * * * * X * * *
+                                                  //|
+                                                  //| * * * * * X * *
+                                                  //| * * X * * * * *
+                                                  //| * * * * * * X *
+                                                  //| * * * X * * * *
+                                                  //| X * * * * * * *
+                                                  //| * * * * * * * X
+                                                  //| * X * * * * * *
+                                                  //| * * * * X * * *
+                                                  //|
+                                                  //| * * * * * X * *
+                                                  //| * * * X * * * *
+                                                  //| X * * * * * * *
+                                                  //| * * * * X * * *
+                                                  //| * * * * * * * X
+                                                  //| * X * * * * * *
+                                                  //| * * * * * * X *
+                                                  //| * * X * * * * *
+                                                  //|
+                                                  //| * * * * X * * *
+                                                  //| * * * * * * X *
+                                                  //| * X * * * * * *
+                                                  //| * * * X * * * *
+                                                  //| * * * * * * * X
+                                                  //| X * * * * * * *
+                                                  //| * * X * * * * *
+                                                  //| * * * * * X * *
+                                                  //|
+                                                  //| * X * * * * * *
+                                                  //| * * * * * X * *
+                                                  //| X * * * * * * *
+                                                  //| * * * * * * X *
+                                                  //| * * * X * * * *
+                                                  //| * * * * * * * X
+                                                  //| * * X * * * * *
+                                                  //| * * * * X * * *
+                                                  //|
+                                                  //| * * * * * X * *
+                                                  //| * * * X * * * *
+                                                  //| * X * * * * * *
+                                                  //| * * * * * * * X
+                                                  //| * * * * X * * *
+                                                  //| * * * * * * X *
+                                                  //| X * * * * * * *
                                                   //| * * X * * * * * "
-  
+
   def isSafe(row: Int, col: Int, queens: List[Int]) =
-    queens zip (row - 1 to 0 by -1) forall {
-      case (r, c) => col != c && (row - r) != math.abs(col - c)
-    }                                             //> isSafe: (row: Int, col: Int, queens: List[Int])Boolean
+    queens.zip(row - 1 to 0 by -1).forall(
+      (r, c) => col != c && (row - r) != math.abs(col - c)
+    )                                            //> isSafe: (row: Int, col: Int, queens: List[Int])Boolean
 }
\ No newline at end of file