Add filter, fold and summary slides for "Recursion patterns" section
This commit is contained in:
		
							parent
							
								
									729c460112
								
							
						
					
					
						commit
						cd8f11e259
					
				
							
								
								
									
										154
									
								
								VL2.tex
									
									
									
									
									
								
							
							
						
						
									
										154
									
								
								VL2.tex
									
									
									
									
									
								
							@ -501,4 +501,158 @@ absList = map abs
 | 
			
		||||
Cool, right? So now we have abstracted out the \textbf{recursion pattern} that is all the same for those 3 functions. \code{map} is actually part of the standard library (called \emph{Prelude}).
 | 
			
		||||
\end{frame}
 | 
			
		||||
 | 
			
		||||
\subsection{6.2. filter}
 | 
			
		||||
 | 
			
		||||
\begin{frame}[fragile]
 | 
			
		||||
\frametitle{6.2. filter}
 | 
			
		||||
Imagine we want to filter all even numbers of a list and throw away all others. I'll give you the type signature:
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
filterEven :: [Int] -> [Int]
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
Solution?
 | 
			
		||||
\pause
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
filterEven :: [Int] -> [Int]
 | 
			
		||||
filterEven [] = []
 | 
			
		||||
filterEven (x:xs)
 | 
			
		||||
  | even x    = x : filterEven xs
 | 
			
		||||
  | otherwise = filterEven xs
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
\pause
 | 
			
		||||
Or: filter out all 0's, so we can count them later:
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
filterZero :: [Int] -> [Int]
 | 
			
		||||
filterZero [] = []
 | 
			
		||||
filterZero (x:xs)
 | 
			
		||||
  | x == 0    = x : filterZero xs
 | 
			
		||||
  | otherwise = filterZero xs
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
Again: do you notice something?
 | 
			
		||||
\end{frame}
 | 
			
		||||
 | 
			
		||||
\begin{frame}[fragile]
 | 
			
		||||
\frametitle{6.2. filter (ctn.)}
 | 
			
		||||
Let's abstract out the common pieces! This will be our type signature:
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
filter :: (a -> Bool) -> [a] -> [a]
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
Solution?
 | 
			
		||||
\pause
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
filter :: (a -> Bool) -> [a] -> [a]
 | 
			
		||||
filter f [] = []
 | 
			
		||||
filter f (x:xs)
 | 
			
		||||
  | f x       = x : filter f xs
 | 
			
		||||
  | otherwise = filter f xs
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
Again: this function is part of the \emph{Prelude} as well.
 | 
			
		||||
\end{frame}
 | 
			
		||||
 | 
			
		||||
\subsection{6.3. fold}
 | 
			
		||||
 | 
			
		||||
\begin{frame}[fragile]
 | 
			
		||||
\frametitle{6.3. fold}
 | 
			
		||||
There's one more important recursion pattern. Imagine you want the sum of all  numbers of a list, so the function type signature would be:
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
sum :: [Int] -> Int
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
Solution?
 | 
			
		||||
\pause
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
sum :: [Int] -> Int
 | 
			
		||||
sum [] = 0
 | 
			
		||||
sum (x:xs) = x + sum xs
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
\pause
 | 
			
		||||
Or the product:
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
prod :: [Int] -> Int
 | 
			
		||||
prod [] = 1
 | 
			
		||||
prod (x:xs) = x * prod xs
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
\pause
 | 
			
		||||
Or the length:
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
length :: [a] -> Int
 | 
			
		||||
length [] = 0
 | 
			
		||||
length (x:xs) = 1 + length xs
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
\end{frame}
 | 
			
		||||
 | 
			
		||||
\begin{frame}[fragile]
 | 
			
		||||
\frametitle{6.3. fold (ctn.)}
 | 
			
		||||
To cut the story short, the abstract solution looks like this:
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
fold :: b -> (a -> b -> b) -> [a] -> b
 | 
			
		||||
fold z f []     = z
 | 
			
		||||
fold z f (x:xs) = f x (fold z f xs)
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
Whoa! What's going on here?\\
 | 
			
		||||
Let's see...
 | 
			
		||||
\begin{itemize}[<+->]
 | 
			
		||||
\item \code{z} is what we return if the list is empty
 | 
			
		||||
\item \code{f} is our function (e.g. \code{(*)} or \code{(+)})
 | 
			
		||||
\item and the last remaining argument is the actual list we are working on
 | 
			
		||||
\end{itemize}
 | 
			
		||||
\onslide<+->
 | 
			
		||||
The function application has the following form:\\
 | 
			
		||||
\code{fold f z [a,b,c] == a `f` (b `f` (c `f` z))}
 | 
			
		||||
\vspace{\baselineskip}
 | 
			
		||||
\\
 | 
			
		||||
This folds from the right, so the \emph{Prelude} already defines a function which is very similar to ours and called \textbf{foldr}.
 | 
			
		||||
\end{frame}
 | 
			
		||||
 | 
			
		||||
\begin{frame}[fragile]
 | 
			
		||||
\frametitle{6.3. fold (ctn.)}
 | 
			
		||||
So how do our \code{sum}, \code{prod} and \code{length} functions look like if we use our \code{fold} abstraction?
 | 
			
		||||
\pause
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
sum :: [Int] -> Int
 | 
			
		||||
sum xs = fold 0 (\x y -> x + y) xs
 | 
			
		||||
-- a Haskeller would write
 | 
			
		||||
sum = fold 0 (+)
 | 
			
		||||
 | 
			
		||||
prod :: [Int] -> Int
 | 
			
		||||
prod xs = fold 1 (\x y -> x * y) xs
 | 
			
		||||
 | 
			
		||||
length :: [a] -> Int
 | 
			
		||||
length xs = fold 0 (\x y -> 1 + y) xs
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
\end{frame}
 | 
			
		||||
 | 
			
		||||
\begin{frame}[fragile]
 | 
			
		||||
\frametitle{6.3. fold (ctn.)}
 | 
			
		||||
There is also a function that folds from the \emph{left} which is also in the \emph{Prelude} and called \textbf{foldl}.\\
 | 
			
		||||
To summarize:
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
foldr f z [a,b,c] == a `f` (b `f` (c `f` z))
 | 
			
		||||
foldl f z [a,b,c] == ((z `f` a) `f` b) `f` c
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
For \code{foldl} the \code{z} is sort of the starting value.
 | 
			
		||||
\vspace{\baselineskip}
 | 
			
		||||
\\
 | 
			
		||||
\pause
 | 
			
		||||
We can even express foldl in terms of foldr and vice versa. If you are interested, have a look here: \url{http://lambda.jstolarek.com/2012/07/expressing-foldl-in-terms-of-foldr/}
 | 
			
		||||
\vspace{\baselineskip}
 | 
			
		||||
\\
 | 
			
		||||
You should definitely look them up in the Prelude and play with them: \url{https://hackage.haskell.org/package/base-4.8.0.0/docs/Prelude.html}
 | 
			
		||||
\vspace{\baselineskip}
 | 
			
		||||
\\
 | 
			
		||||
GHCi...
 | 
			
		||||
\begin{haskellcode}
 | 
			
		||||
> foldr (-) 0 [1, 2, 3]
 | 
			
		||||
> foldl (-) 0 [1, 2, 3]
 | 
			
		||||
\end{haskellcode}
 | 
			
		||||
\end{frame}
 | 
			
		||||
 | 
			
		||||
\begin{frame}[fragile]
 | 
			
		||||
\frametitle{6.3. summary}
 | 
			
		||||
\begin{itemize}[<+->]
 | 
			
		||||
\item if you find recurring patterns in your code, abstract them out! Experienced Haskellers avoid explicit recursion, unless the recursion pattern is so complex/specific that an abstraction doesn't make sense.
 | 
			
		||||
\item map, filter, fold etc are all dependent on the data type (here: lists). For new data types (e.g. a tree) you can and will write your own recursion abstractions
 | 
			
		||||
\item although these functions are so fundamental that they are already implemented for most data types out there
 | 
			
		||||
\end{itemize}
 | 
			
		||||
\end{frame}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
\end{document}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user