From 86969074e3d241fe95397bde0a75f2dfb9d3c4f0 Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Mon, 20 Apr 2015 00:32:50 +0200 Subject: [PATCH] VL2: Restructure files, add proper article/handout version --- VL2.tex | 557 ++++---------------------------------- VL2_composition1.tex | 21 ++ VL2_composition2.tex | 18 ++ VL2_composition3.tex | 25 ++ VL2_currying1.tex | 13 + VL2_currying2.tex | 4 + VL2_currying3.tex | 18 ++ VL2_currying4.tex | 7 + VL2_currying5.tex | 16 ++ VL2_currying6.tex | 21 ++ VL2_currying7.tex | 12 + VL2_currying8.tex | 6 + VL2_define_functions1.tex | 17 ++ VL2_define_functions2.tex | 8 + VL2_define_functions3.tex | 6 + VL2_define_functions4.tex | 17 ++ VL2_define_functions5.tex | 12 + VL2_handout.tex | 147 ++++++++++ VL2_polymorphism1.tex | 20 ++ VL2_polymorphism2.tex | 20 ++ VL2_polymorphism3.tex | 0 VL2_rec_patterns1.tex | 9 + VL2_rec_patterns10.tex | 14 + VL2_rec_patterns11.tex | 21 ++ VL2_rec_patterns12.tex | 5 + VL2_rec_patterns2.tex | 7 + VL2_rec_patterns3.tex | 23 ++ VL2_rec_patterns4.tex | 16 ++ VL2_rec_patterns5.tex | 15 + VL2_rec_patterns6.tex | 23 ++ VL2_rec_patterns7.tex | 14 + VL2_rec_patterns8.tex | 25 ++ VL2_rec_patterns9.tex | 19 ++ VL2_reflection1.tex | 7 + VL2_reflection2.tex | 9 + VL2_reiteration.tex | 6 + 36 files changed, 675 insertions(+), 503 deletions(-) create mode 100644 VL2_composition1.tex create mode 100644 VL2_composition2.tex create mode 100644 VL2_composition3.tex create mode 100644 VL2_currying1.tex create mode 100644 VL2_currying2.tex create mode 100644 VL2_currying3.tex create mode 100644 VL2_currying4.tex create mode 100644 VL2_currying5.tex create mode 100644 VL2_currying6.tex create mode 100644 VL2_currying7.tex create mode 100644 VL2_currying8.tex create mode 100644 VL2_define_functions1.tex create mode 100644 VL2_define_functions2.tex create mode 100644 VL2_define_functions3.tex create mode 100644 VL2_define_functions4.tex create mode 100644 VL2_define_functions5.tex create mode 100644 VL2_handout.tex create mode 100644 VL2_polymorphism1.tex create mode 100644 VL2_polymorphism2.tex create mode 100644 VL2_polymorphism3.tex create mode 100644 VL2_rec_patterns1.tex create mode 100644 VL2_rec_patterns10.tex create mode 100644 VL2_rec_patterns11.tex create mode 100644 VL2_rec_patterns12.tex create mode 100644 VL2_rec_patterns2.tex create mode 100644 VL2_rec_patterns3.tex create mode 100644 VL2_rec_patterns4.tex create mode 100644 VL2_rec_patterns5.tex create mode 100644 VL2_rec_patterns6.tex create mode 100644 VL2_rec_patterns7.tex create mode 100644 VL2_rec_patterns8.tex create mode 100644 VL2_rec_patterns9.tex create mode 100644 VL2_reflection1.tex create mode 100644 VL2_reflection2.tex create mode 100644 VL2_reiteration.tex diff --git a/VL2.tex b/VL2.tex index 669a7e0..67c3e33 100644 --- a/VL2.tex +++ b/VL2.tex @@ -37,6 +37,10 @@ % macros and environments \newcommand{\code}[1]{\texttt{#1}} +\newcommand{\slidep}{\onslide<+->} +\newenvironment{itemizep} + {\begin{itemize}[<+->]} + {\end{itemize}} \begin{document} @@ -56,12 +60,7 @@ \begin{frame} \frametitle{1. Reiteration (ctn.)} -\begin{itemize} -\item What is haskell? What are the 3 fundamental concepts behind it? -\item How do you do pattern matching? -\item What is the difference between lists and tuples? How do you construct them? -\item How do you define your own data types? -\end{itemize} +\input{VL2_reiteration.tex} \end{frame} \section{2. Polymorphism} @@ -73,145 +72,52 @@ \begin{frame}[fragile] \frametitle{2. Polymorphism (ctn.)} -So when we said that haskell is good for abstraction, what did we actually mean? Do we have something like java generics or C++ templates? -\vspace{\baselineskip} -\\ -\pause -Even better! Haskell supports polymorphism for both data types and functions.\\ -Let's start with a polymorphic data type: -\begin{haskellcode} -data List t = Empty | Cons t (List t) -\end{haskellcode} -So we just implemented our own singly-linked List. For any type! Let's use it: -\pause -\begin{haskellcode} -intList :: List Int -intList = Cons 3 (Cons 5 (Cons 2 Empty)) - -charList :: List Char -charList = Cons 'x' (Cons 'y' (Cons 'z' Empty)) - --- whatever you can imagine goes here -\end{haskellcode} +\input{VL2_polymorphism1.tex} \end{frame} \begin{frame}[fragile] \frametitle{2. Polymorphism (ctn.)} -And now we are going to write functions to use it: -\begin{haskellcode} -isListEmpty :: List t -> Bool -isListEmpty Emtpy = True -isListEmpty x = False -\end{haskellcode} -\pause -We can even have more generic stuff like: -\begin{haskellcode} -f :: a -> b -\end{haskellcode} -Whatever the function does... it has something of one type and returns something of another type (it could be the same type, but doesn't need to). That's all we know. -\vspace{\baselineskip} -\\ -\pause -Similarly, remember the function \code{head} which gives us the first element of a list? The type signature actually looks like this: -\begin{haskellcode} -head :: [a] -> a -\end{haskellcode} -Makes sense? +\input{VL2_polymorphism2.tex} \end{frame} \section{3. More ways to define functions} \begin{frame} -\frametitle{6. More ways to define functions} +\frametitle{3. More ways to define functions} \tableofcontents[currentsection,hideothersubsections] \end{frame} \begin{frame}[fragile] \frametitle{3. More ways to define functions (ctn.)} -Now you know how a regular function looks like, e.g: -\begin{haskellcode} -f :: Int -> Int -f x = x + 1 -\end{haskellcode} -But now imagine we need a helper function which is very specific to the current function. In C we would have to define this new helper function at top-level and would probably make it \code{static}. -\pause -\vspace{\baselineskip} -\\ -Haskell allows us to \textbf{inline} functions in a few more ways, e.g.: -\begin{itemize}[<+->] -\item with \code{where} -\item with \code{let...in} -\item anonymously (lambda abstraction) -\end{itemize} -\onslide<+-> -A lot of Haskellers really dislike if you put non-generic functions at the top level. So you can still have atomic pieces, but inline the parts which are very specific to the current function. +\input{VL2_define_functions1.tex} \end{frame} \subsection{3.1. Where} \begin{frame}[fragile] \frametitle{3.1. Where} -We use \code{where} to define a helper function: -\begin{haskellcode} -f :: Int -> Int -f x = x + (y 2) - where - y :: Int -> Int - y p = x + p -\end{haskellcode} +\input{VL2_define_functions2.tex} \end{frame} \subsection{3.2. Let} \begin{frame}[fragile] \frametitle{3.2. Let} -Another way which is very similar would be using \code{let}: -\begin{haskellcode} -f :: Int -> Int -f x = let y p = x + p - in x + (y 2) -\end{haskellcode} +\input{VL2_define_functions3.tex} \end{frame} \subsection{3.3. Let vs Where} \begin{frame}[fragile] \frametitle{3.3. Let vs Where} -These look almost the same, but they are different constructs. \code{where} is bound to the pattern matching \code{f x =} and may also have access to parts of a function that are not syntactically expressions, e.g.: -\begin{haskellcode} -f x - | cond1 x = a - | cond2 x = g a - | otherwise = f (h x a) - where - a = w x -\end{haskellcode} -While that is not possible with \code{let}, which is an actual expression and can be used whenever expressions are allowed (e.g. inside \emph{Monads}, we'll know more about these in a few weeks). -\vspace{\baselineskip} -\\ -There are a few more intricacies, but most of the time this is just style consideration:\\ \url{https://wiki.haskell.org/Let_vs._Where} -\pause -\vspace{\baselineskip} -\\ -How would we have to rewrite the function in order to use \code{let}? +\input{VL2_define_functions4.tex} \end{frame} \subsection{3.4. Anonymous functions} \begin{frame}[fragile] \frametitle{3.4. Anonymous functions} -We can also have \textbf{anonymous functions} which just means the function doesn't have a name: -\begin{haskellcode} -f :: Int -> Int -f x = (\y -> y + 1) x -\end{haskellcode} -\pause -Although this is basically the same as: -\begin{haskellcode} -f :: Int -> Int -f x = x + 1 -\end{haskellcode} -Anonymous functions will come extremely handy later, you'll see. +\input{VL2_define_functions5.tex} \end{frame} \section{4. Currying} @@ -223,131 +129,42 @@ Anonymous functions will come extremely handy later, you'll see. \begin{frame}[fragile] \frametitle{4. Currying (ctn.)} -This is what actually makes haskell such a fine functional language. You might have noticed that I tried hard to not show type signatures of functions that have more than one argument. Well, that's because we have to dig a little deeper to explain what comes next: -\pause -\begin{haskellcode} -addInt :: Int -> Int -> Int -addInt x y = x + y -\end{haskellcode} -\pause -So, what is happening here? You probably expected something like: -\begin{haskellcode} -addInt :: (Int, Int) -> Int -addInt (x, y) = x + y -\end{haskellcode} -which is actually pretty close. +\input{VL2_currying1.tex} \end{frame} \begin{frame}[fragile] \frametitle{4. Currying (ctn.)} -Currying is actually a mathematical thing and is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple) into evaluating a sequence of functions, each with a single argument. -\vspace{\baselineskip} -\\ -Let that sink in a little bit and read it again. +\input{VL2_currying2.tex} \end{frame} \begin{frame}[fragile] \frametitle{4. Currying (ctn.)} -Maybe a mathematical example will make things clearer. Let's say we have the function:\\ -$f(x, y) = y / x$ -\vspace{\baselineskip} -\\ -\pause -In order to evaluate the function for $x = 2$ and $y = 3$ we would do:\\ -$f(2, 3) = 2 / 3$\\ -and be done. -\vspace{\baselineskip} -\\ -\pause -However, how about we just put in x first and make a new function. Since x is gone, we can write:\\ -$g(y) = f(2, y) = y / 2$ -\vspace{\baselineskip} -\\ -\pause -And in a second step we solve the function $g(y)$:\\ -$g(3) = f (2, 3) = 3 / 2$ +\input{VL2_currying3.tex} \end{frame} \begin{frame}[fragile] \frametitle{4. Currying (ctn.)} -You can also imagine this geometrically:\\ -$z = f(x, y)$ is 3-dimensional. If you fix the variable $x$ you'll make things 2-dimensional (the intersecting plane). If you then fix $y$ you'll get an actual point $z$. -\vspace{\baselineskip} -\\ -\includegraphics*[scale=0.4]{Grafico_3d_x2+xy+y2.png} -\\ -For every of these steps we can define a real new function. This scales up to any number of dimensions/arguments. +\input{VL2_currying4.tex} \end{frame} \begin{frame}[fragile] \frametitle{4. Currying (ctn.)} -So in mathematical terms you can say:\\ -$f : A_1 \times ... \times A_n \mapsto B$ -\vspace{\baselineskip} -\\ -gets modified into:\\ -\pause -$f' : A_1 \mapsto (A_2 \mapsto (\ ...\ (A_n \mapsto B)))$ -\vspace{\baselineskip} -\\ -\pause -Did you just notice the braces? They are \textbf{very} important! So, currying is \emph{right}-associative which means that these two signatures are equivalent: -\begin{haskellcode} -f :: Int -> Int -> Int -f :: Int -> (Int -> Int) -\end{haskellcode} -On the other hand function application is \emph{left}-associative, so \code{f 3 2} is just a shorthand of \code{(f 3) 2}. Makes sense? +\input{VL2_currying5.tex} \end{frame} \begin{frame}[fragile] \frametitle{4. Currying (ctn.)} -What does that mean for us? It's not just fun stuff or aesthetic. It allows us to do \textbf{partial application}. That means we do not have to give a function all arguments. If we pass an "insufficient" number of arguments it will just give us a new function! Here: -\pause -\begin{haskellcode} -addInt :: Int -> Int -> Int -addInt x y = x + y - -addTwo :: Int -> Int -addTwo = addInt 2 -\end{haskellcode} -You probably noticed that we did not write \code{addTwo x = ...}, but why would we? We gave \code{addInt} one argument, so the arity (we called it dimension in the gemoetrical example) is one less, but there is still one parameter left we can pass in. -\vspace{\baselineskip} -\\ -\pause -The reason we can omit the \code{x} here is that -\begin{haskellcode} -f x y z = ... -\end{haskellcode} -is just syntax sugar for -\begin{haskellcode} -f = \x -> (\y -> (\z -> ... )) -- right-associative, ofc -\end{haskellcode} +\input{VL2_currying6.tex} \end{frame} \begin{frame}[fragile] \frametitle{4. Currying (ctn.)} -As said in the beginning of this section, these two look pretty similar: -\begin{haskellcode} -f :: Int -> Int -> Int - -f :: (Int, Int) -> Int -\end{haskellcode} -And we now know that we can convert from one to another. Of course haskell also provides us two functions to do that, here we go: -\begin{haskellcode} -curry :: ((a, b) -> c) -> a -> b -> c - -uncurry :: (a -> b -> c) -> (a, b) -> c -\end{haskellcode} +\input{VL2_currying7.tex} \end{frame} \begin{frame}[fragile] \frametitle{4. Currying (ctn.)} -So... now that we know what currying is, let's summarize: -\begin{itemize}[<+->] -\item all functions in haskell have only one argument (strictly speaking) -\item if a function seems to have multiple arguments... currying is used behind the scenes to evaluate it -\item currying also allows us to do partial function application (which is important for function composition) -\end{itemize} +\input{VL2_currying8.tex} \end{frame} \section{5. Function composition} @@ -360,78 +177,17 @@ So... now that we know what currying is, let's summarize: \begin{frame}[fragile] \frametitle{5. Function composition (ctn.)} -So why did we just bother so long with explaining currying? It's because it's very important for function composition. Which again is also one of the fundamental concepts of functional programming. -\vspace{\baselineskip} -\\ -From maths we already know that:\\ -$(g \circ f)(x) = g(f(x))$ -\vspace{\baselineskip} -\\ -\pause -And that's basically it. We do the same in haskell, it looks like this: -\begin{haskellcode} -composedFunction x = (f . g) x - --- same as above... everything on the right side of $ --- is evaluated first -composedFunction x = f . g $ x - --- and same again, remember that 'f x =' --- is just syntax sugar --- omitting the x here is also called eta reduction -composedFunction = f . g -\end{haskellcode} +\input{VL2_composition1.tex} \end{frame} \begin{frame}[fragile] \frametitle{5. Function composition} -But let's not stop here. What does the dot \code{(.)} actually mean? -\vspace{\baselineskip} -\\ -\pause -It's just a function (the \emph{prefix} version of \code{.})! Here is the type signature: -\begin{haskellcode} -(.) :: (b -> c) -> (a -> b) -> a -> c -\end{haskellcode} -\pause -\textbf{Exercise:} Implement it! It's really just one line! Remember the mathematical definition. -\vspace{\baselineskip} -\\ -\pause -Solution: -\begin{haskellcode} -(.) :: (b -> c) -> (a -> b) -> a -> c -(.) f g x = f (g x) -\end{haskellcode} +\input{VL2_composition2.tex} \end{frame} \begin{frame}[fragile] \frametitle{5. Function composition} -And now you can chain functions together. Not just two! Look: -\begin{haskellcode} -f :: String -> Bool -f xs = (even . length . (\x -> x ++ "Hello world")) xs --- or less ugly -f xs = even . length . (\x -> x ++ "Hello world") $ xs -\end{haskellcode} -% $ -\pause -Another example where currying is actually important: -\begin{haskellcode} -f :: Int -> Bool -f x = even . (+) 3 . (-) 4 $ x - --- why not this? -f x = even . (+) 3 . (-) $ 4 x -\end{haskellcode} -%$ -\pause -So there are a few things that we have to be aware of: -\begin{itemize} -\item the types have to fit! -\item the arity has to fit! -\end{itemize} -That sounds complicated at first, because it counts for the whole composition chain. But you'll get used to it. +\input{VL2_composition3.tex} \end{frame} \section{6. Recursion patterns} @@ -443,247 +199,68 @@ That sounds complicated at first, because it counts for the whole composition ch \begin{frame}[fragile] \frametitle{6. Recursion patterns (ctn.)} -Since we use lists a lot in haskell, we also want some more powerful functions to deal with them. E.g.: -\begin{itemize} -\item perform an operation on every element on a list -\item keep only some elements in the list, following some criteria -\item "summarize" the elements of the list somehow -\item ... -\end{itemize} -\pause -How do we do that? +\input{VL2_rec_patterns1.tex} \end{frame} -\subsection{6.1. map} +\subsection{6.1. Map} \begin{frame}[fragile] -\frametitle{6.1. map} -Let's say we have a list of \code{Int} and want to add \code{2} to every element of the list. -\begin{haskellcode} -addTwo :: [Int] -> [Int] -addTwo ... ? -\end{haskellcode} -\pause -\textbf{Exercise:} Find the answer! 5 minutes time, remember the \emph{cons} operator \code{(:)}, pattern matching on lists and ofc recursion! Start with the case of an empty list. +\frametitle{6.1. Map} +\input{VL2_rec_patterns2.tex} \end{frame} \begin{frame}[fragile] -\frametitle{6.1. map (ctn.)} -Solution? -\begin{haskellcode} -addTwo :: [Int] -> [Int] -addTwo [] = [] -addTwo (x:xs) = (x + 2) : addTwo xs -\end{haskellcode} -\pause -Now we want to square every element: -\pause -\begin{haskellcode} -square :: [Int] -> [Int] -square [] = [] -square (x:xs) = (x * x) : square xs -\end{haskellcode} -\pause -Now we want the absolute of every element: -\begin{haskellcode} -absList :: [Int] -> [Int] -absList [] = [] -absList (x:xs) = (abs x) : absList xs -\end{haskellcode} -\pause -Do you notice something? +\frametitle{6.1. Map (ctn.)} +\input{VL2_rec_patterns3.tex} \end{frame} \begin{frame}[fragile] -\frametitle{6.1. map (ctn.)} -All those 3 functions look almost the same. Since haskell is about abstraction, we would never really write any of those like that. Instead, we will write a function that generalizes all 3. -\vspace{\baselineskip} -\\ -\pause -I'll give you the type signature, can you guess how the implementation looks like? -\begin{haskellcode} -map :: (a -> b) -> [a] -> [b] -\end{haskellcode} -Solution? -\pause -\begin{haskellcode} -map :: (a -> b) -> [a] -> [b] -map f [] = [] -map f (x:xs) = f x : map f xs -\end{haskellcode} -So we don't really know what the function \code{f} does, but we know that it converts one element of the list to something else. We \emph{map} a function over a list! Hence the name. +\frametitle{6.1. Map (ctn.)} +\input{VL2_rec_patterns4.tex} \end{frame} \begin{frame}[fragile] -\frametitle{6.1. map (ctn.)} -And now watch this: -\begin{haskellcode} -addTwo :: [Int] -> [Int] -addTwo xs = map (\x -> x + 2) xs - -square :: [Int] -> [Int] -square xs = map (\x -> x * x) xs - -absList :: [Int] -> [Int] -absList xs = map (\x -> abs x) xs --- a haskeller would write, GHCi... -absList = map abs -\end{haskellcode} -\pause -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}). +\frametitle{6.1. Map (ctn.)} +\input{VL2_rec_patterns5.tex} \end{frame} -\subsection{6.2. filter} +\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? +\frametitle{6.2. Filter} +\input{VL2_rec_patterns6.tex} \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. +\frametitle{6.2. Filter (ctn.)} +\input{VL2_rec_patterns7.tex} \end{frame} -\subsection{6.3. fold} +\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} +\frametitle{6.3. Fold} +\input{VL2_rec_patterns8.tex} \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}. +\frametitle{6.3. Fold (ctn.)} +\input{VL2_rec_patterns9.tex} \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} +\frametitle{6.3. Fold (ctn.)} +\input{VL2_rec_patterns10.tex} \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} +\frametitle{6.3. Fold (ctn.)} +\input{VL2_rec_patterns11.tex} \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} +\frametitle{6.3. Summary} +\input{VL2_rec_patterns12.tex} \end{frame} \section{7. Reflection} @@ -696,28 +273,14 @@ GHCi... \begin{frame} \frametitle{7.1. What you should know now} -\begin{itemize} -\item how to write polymorphic data types and functions -\item how you inline functions -\item what currying is and why we need it in haskell -\item how you compose functions -\item how to abstract out recursion patterns -\end{itemize} +\input{VL2_reflection1.tex} \end{frame} \subsection{7.2. Questions for you} \begin{frame}[fragile] \frametitle{7.2. Questions for you} -\begin{itemize} -\item what is the difference between \code{let} and \code{where}? -\item what is the difference between \code{foldr} and \code{foldl}? -\item what is the difference between explicit and implicit recursion? Give examples -\item how many arguments does a haskell function have (strictly speaking)? -\item what do you have to keep in mind in order to make function composition work? -\item can you define map and filter in terms of foldr? -\item what is eta reduction (or: eta abstraction)? -\end{itemize} +\input{VL2_reflection2.tex} \end{frame} \section{8. References} @@ -731,26 +294,14 @@ GHCi... \begin{frame} \frametitle{8.1. Further reading and useful links} -\begin{itemize} -\item the most popular haskell course from Brent Yorgey:\\ \url{https://www.seas.upenn.edu/~cis194/fall14/spring13/lectures.html} -\item very verbose and enthusiastic haskell book, good for reading once:\\ \url{http://learnyouahaskell.com} -\item collection of websites teaching haskell:\\ \url{https://github.com/bitemyapp/learnhaskell} -\item haskell programming tips (and wiki):\\ \url{https://wiki.haskell.org/Haskell_programming_tips} -\item the standard module (similar to libc in C):\\ \url{https://hackage.haskell.org/package/base-4.7.0.0/docs/Prelude.html} -\item debugging in haskell:\\ \url{https://wiki.haskell.org/Debugging} -\end{itemize} +\input{VL_links.tex} \end{frame} \subsection{8.2. Sources} \begin{frame} \frametitle{8.2. Sources} -\begin{itemize} -\item much content was borrowed or is based on the haskell course from Brent Yorgey:\\ \url{https://www.seas.upenn.edu/~cis194/fall14/spring13/lectures.html} -\item a few small pieces from the LYAH book \url{http://learnyouahaskell.com} -\item general information from wikipedia: \\ \url{https://en.wikipedia.org} -\item general information from haskell wiki: \\ \url{https://wiki.haskell.org} -\end{itemize} +\input{VL_sources.tex} \end{frame} \end{document} \ No newline at end of file diff --git a/VL2_composition1.tex b/VL2_composition1.tex new file mode 100644 index 0000000..b3e9b2b --- /dev/null +++ b/VL2_composition1.tex @@ -0,0 +1,21 @@ +So why did we just bother so long with explaining currying? It's because it's very important for function composition. Which again is also one of the fundamental concepts of functional programming. +\vspace{\baselineskip} +\\ +From maths we already know that:\\ +$(g \circ f)(x) = g(f(x))$ +\vspace{\baselineskip} +\\ +\pause +And that's basically it. We do the same in haskell, it looks like this: +\begin{haskellcode} +composedFunction x = (f . g) x + +-- same as above... everything on the right side of $ +-- is evaluated first +composedFunction x = f . g $ x + +-- and same again, remember that 'f x =' +-- is just syntax sugar +-- omitting the x here is also called eta reduction +composedFunction = f . g +\end{haskellcode} \ No newline at end of file diff --git a/VL2_composition2.tex b/VL2_composition2.tex new file mode 100644 index 0000000..b2cf0b6 --- /dev/null +++ b/VL2_composition2.tex @@ -0,0 +1,18 @@ +But let's not stop here. What does the dot \code{(.)} actually mean? +\vspace{\baselineskip} +\\ +\pause +It's just a function (the \emph{prefix} version of \code{.})! Here is the type signature: +\begin{haskellcode} +(.) :: (b -> c) -> (a -> b) -> a -> c +\end{haskellcode} +\pause +\textbf{Exercise:} Implement it! It's really just one line! Remember the mathematical definition. +\vspace{\baselineskip} +\\ +\pause +Solution: +\begin{haskellcode} +(.) :: (b -> c) -> (a -> b) -> a -> c +(.) f g x = f (g x) +\end{haskellcode} \ No newline at end of file diff --git a/VL2_composition3.tex b/VL2_composition3.tex new file mode 100644 index 0000000..07702aa --- /dev/null +++ b/VL2_composition3.tex @@ -0,0 +1,25 @@ +And now you can chain functions together. Not just two! Look: +\begin{haskellcode} +f :: String -> Bool +f xs = (even . length . (\x -> x ++ "Hello world")) xs +-- or less ugly +f xs = even . length . (\x -> x ++ "Hello world") $ xs +\end{haskellcode} +% $ +\pause +Another example where currying is actually important: +\begin{haskellcode} +f :: Int -> Bool +f x = even . (+) 3 . (-) 4 $ x + +-- why not this? +f x = even . (+) 3 . (-) $ 4 x +\end{haskellcode} +%$ +\pause +So there are a few things that we have to be aware of: +\begin{itemize} +\item the types have to fit! +\item the arity has to fit! +\end{itemize} +That sounds complicated at first, because it counts for the whole composition chain. But you'll get used to it. \ No newline at end of file diff --git a/VL2_currying1.tex b/VL2_currying1.tex new file mode 100644 index 0000000..58ece6d --- /dev/null +++ b/VL2_currying1.tex @@ -0,0 +1,13 @@ +This is what actually makes haskell such a fine functional language. You might have noticed that I tried hard to not show type signatures of functions that have more than one argument. Well, that's because we have to dig a little deeper to explain what comes next: +\pause +\begin{haskellcode} +addInt :: Int -> Int -> Int +addInt x y = x + y +\end{haskellcode} +\pause +So, what is happening here? You probably expected something like: +\begin{haskellcode} +addInt :: (Int, Int) -> Int +addInt (x, y) = x + y +\end{haskellcode} +which is actually pretty close. \ No newline at end of file diff --git a/VL2_currying2.tex b/VL2_currying2.tex new file mode 100644 index 0000000..b5fdebf --- /dev/null +++ b/VL2_currying2.tex @@ -0,0 +1,4 @@ +Currying is sort of a mathematical thing and is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple) into evaluating a sequence of functions, each with a single argument. +\vspace{\baselineskip} +\\ +Let that sink in a little bit and read it again. \ No newline at end of file diff --git a/VL2_currying3.tex b/VL2_currying3.tex new file mode 100644 index 0000000..5264e6f --- /dev/null +++ b/VL2_currying3.tex @@ -0,0 +1,18 @@ +Maybe a mathematical example will make things clearer. Let's say we have the function:\\ +$f(x, y) = y / x$ +\vspace{\baselineskip} +\\ +\pause +In order to evaluate the function for $x = 2$ and $y = 3$ we would do:\\ +$f(2, 3) = 2 / 3$\\ +and be done. +\vspace{\baselineskip} +\\ +\pause +However, how about we just put in x first and make a new function. Since x is gone, we can write:\\ +$g(y) = f(2, y) = y / 2$ +\vspace{\baselineskip} +\\ +\pause +And in a second step we solve the function $g(y)$:\\ +$g(3) = f (2, 3) = 3 / 2$ \ No newline at end of file diff --git a/VL2_currying4.tex b/VL2_currying4.tex new file mode 100644 index 0000000..23dfca5 --- /dev/null +++ b/VL2_currying4.tex @@ -0,0 +1,7 @@ +You can also imagine this geometrically:\\ +$z = f(x, y)$ is 3-dimensional. If you fix the variable $x$ you'll make things 2-dimensional (the intersecting plane). If you then fix $y$ you'll get an actual point $z$. +\vspace{\baselineskip} +\\ +\includegraphics*[scale=0.4]{Grafico_3d_x2+xy+y2.png} +\\ +For every of these steps we can define a real new function. This scales up to any number of dimensions/arguments. \ No newline at end of file diff --git a/VL2_currying5.tex b/VL2_currying5.tex new file mode 100644 index 0000000..e92d837 --- /dev/null +++ b/VL2_currying5.tex @@ -0,0 +1,16 @@ +So in mathematical terms you can say:\\ +$f : A_1 \times ... \times A_n \mapsto B$ +\vspace{\baselineskip} +\\ +gets modified into:\\ +\pause +$f' : A_1 \mapsto (A_2 \mapsto (\ ...\ (A_n \mapsto B)))$ +\vspace{\baselineskip} +\\ +\pause +Did you just notice the braces? They are \textbf{very} important! So, currying is \emph{right}-associative which means that these two signatures are equivalent: +\begin{haskellcode} +f :: Int -> Int -> Int +f :: Int -> (Int -> Int) +\end{haskellcode} +On the other hand function application is \emph{left}-associative, so \code{f 3 2} is just a shorthand of \code{(f 3) 2}. Makes sense? \ No newline at end of file diff --git a/VL2_currying6.tex b/VL2_currying6.tex new file mode 100644 index 0000000..67923ba --- /dev/null +++ b/VL2_currying6.tex @@ -0,0 +1,21 @@ +What does that mean for us? It's not just fun stuff or aesthetic. It allows us to do \textbf{partial application}. That means we do not have to give a function all arguments. If we pass an "insufficient" number of arguments it will just give us a new function! Here: +\pause +\begin{haskellcode} +addInt :: Int -> Int -> Int +addInt x y = x + y + +addTwo :: Int -> Int +addTwo = addInt 2 +\end{haskellcode} +You probably noticed that we did not write \code{addTwo x = ...}, but why would we? We gave \code{addInt} one argument, so the arity (we called it dimension in the gemoetrical example) is one less, but there is still one parameter left we can pass in. +\vspace{\baselineskip} +\\ +\pause +The reason we can omit the \code{x} here is that +\begin{haskellcode} +f x y z = ... +\end{haskellcode} +is just syntax sugar for +\begin{haskellcode} +f = \x -> (\y -> (\z -> ... )) -- right-associative, ofc +\end{haskellcode} \ No newline at end of file diff --git a/VL2_currying7.tex b/VL2_currying7.tex new file mode 100644 index 0000000..7a4044e --- /dev/null +++ b/VL2_currying7.tex @@ -0,0 +1,12 @@ +As said in the beginning of this section, these two look pretty similar: +\begin{haskellcode} +f :: Int -> Int -> Int + +f :: (Int, Int) -> Int +\end{haskellcode} +And we now know that we can convert from one to another. Of course haskell also provides us two functions to do that, here we go: +\begin{haskellcode} +curry :: ((a, b) -> c) -> a -> b -> c + +uncurry :: (a -> b -> c) -> (a, b) -> c +\end{haskellcode} \ No newline at end of file diff --git a/VL2_currying8.tex b/VL2_currying8.tex new file mode 100644 index 0000000..319a7cd --- /dev/null +++ b/VL2_currying8.tex @@ -0,0 +1,6 @@ +So... now that we know what currying is, let's summarize: +\begin{itemizep} +\item all functions in haskell have only one argument (strictly speaking) +\item if a function seems to have multiple arguments... currying is used behind the scenes to evaluate it +\item currying also allows us to do partial function application (which is important for function composition) +\end{itemizep} \ No newline at end of file diff --git a/VL2_define_functions1.tex b/VL2_define_functions1.tex new file mode 100644 index 0000000..ee630b0 --- /dev/null +++ b/VL2_define_functions1.tex @@ -0,0 +1,17 @@ +Now you know how a regular function looks like, e.g: +\begin{haskellcode} +f :: Int -> Int +f x = x + 1 +\end{haskellcode} +But now imagine we need a helper function which is very specific to the current function. In C we would have to define this new helper function at top-level and would probably make it \code{static}. +\pause +\vspace{\baselineskip} +\\ +Haskell allows us to \textbf{inline} functions in a few more ways, e.g.: +\begin{itemizep} +\item with \code{where} +\item with \code{let...in} +\item anonymously (lambda abstraction) +\end{itemizep} +\slidep +A lot of Haskellers really dislike if you put non-generic functions at the top level. So you can still have atomic pieces, but inline the parts which are very specific to the current function. \ No newline at end of file diff --git a/VL2_define_functions2.tex b/VL2_define_functions2.tex new file mode 100644 index 0000000..e715bba --- /dev/null +++ b/VL2_define_functions2.tex @@ -0,0 +1,8 @@ +We use \code{where} to define a helper function: +\begin{haskellcode} +f :: Int -> Int +f x = x + (y 2) + where + y :: Int -> Int + y p = x + p +\end{haskellcode} \ No newline at end of file diff --git a/VL2_define_functions3.tex b/VL2_define_functions3.tex new file mode 100644 index 0000000..d18611d --- /dev/null +++ b/VL2_define_functions3.tex @@ -0,0 +1,6 @@ +Another way which is very similar would be using \code{let}: +\begin{haskellcode} +f :: Int -> Int +f x = let y p = x + p + in x + (y 2) +\end{haskellcode} \ No newline at end of file diff --git a/VL2_define_functions4.tex b/VL2_define_functions4.tex new file mode 100644 index 0000000..467c88e --- /dev/null +++ b/VL2_define_functions4.tex @@ -0,0 +1,17 @@ +These look almost the same, but they are different constructs. \code{where} is bound to the pattern matching \code{f x =} and may also have access to parts of a function that are not syntactically expressions, e.g.: +\begin{haskellcode} +f x + | cond1 x = a + | cond2 x = g a + | otherwise = f (h x a) + where + a = w x +\end{haskellcode} +While that is not possible with \code{let}, which is an actual expression and can be used whenever expressions are allowed (e.g. inside \emph{Monads}, we'll know more about these in a few weeks). +\vspace{\baselineskip} +\\ +There are a few more intricacies, but most of the time this is just style consideration:\\ \url{https://wiki.haskell.org/Let_vs._Where} +\pause +\vspace{\baselineskip} +\\ +How would we have to rewrite the function in order to use \code{let}? \ No newline at end of file diff --git a/VL2_define_functions5.tex b/VL2_define_functions5.tex new file mode 100644 index 0000000..e9e050f --- /dev/null +++ b/VL2_define_functions5.tex @@ -0,0 +1,12 @@ +We can also have \textbf{anonymous functions} which just means the function doesn't have a name: +\begin{haskellcode} +f :: Int -> Int +f x = (\y -> y + 1) x +\end{haskellcode} +\pause +Although this is basically the same as: +\begin{haskellcode} +f :: Int -> Int +f x = x + 1 +\end{haskellcode} +Anonymous functions will come extremely handy later, you'll see. \ No newline at end of file diff --git a/VL2_handout.tex b/VL2_handout.tex new file mode 100644 index 0000000..f901050 --- /dev/null +++ b/VL2_handout.tex @@ -0,0 +1,147 @@ +\documentclass[12pt,a4paper,fleqn,oneside]{article} + +% packages +\usepackage{xcolor} +\usepackage[utf8]{inputenc} +\usepackage{amsmath} +\usepackage{amsfonts} +\usepackage{amssymb} +\usepackage{graphicx} +\usepackage{hyperref} +\usepackage{listings} +\usepackage{minted} + +% for \verb inside \item +\usepackage[T1]{fontenc} +\usepackage[Q=yes]{examplep} + +% package configuration +\DeclareGraphicsExtensions{.pdf,.png,.jpg} +\usemintedstyle{friendly} +\newminted{haskell}{frame=single,numbers=left,samepage=true} +\newminted{cpp}{frame=single,numbers=left} +\newminted{c}{frame=single,numbers=left} +\renewcommand{\theFancyVerbLine}{\ttfamily + \textcolor[rgb]{0.0,0.0,0.0}{\footnotesize + \oldstylenums{\arabic{FancyVerbLine}}}} + +% macros and environments +\newcommand{\code}[1]{\texttt{#1}} +\newcommand{\pause}{} +\newcommand{\slidep}{} +\newenvironment{itemizep} + {\begin{itemize}} + {\end{itemize}} + +% color definition +\definecolor{solarized}{HTML}{002B36} +\definecolor{mygreen}{rgb}{0,0.6,0} + + +\begin{document} + +% title page information +\author{Julian Ospald} +\title{Haskell: higher order functions} + +\maketitle + +\tableofcontents + +\section{Reiteration} + +\input{VL2_reiteration.tex} + + +\section{Polymorphism} + +\input{VL2_polymorphism1.tex} +\input{VL2_polymorphism2.tex} +\input{VL2_polymorphism3.tex} + + +\section{More ways to define functions} + +\input{VL2_define_functions1.tex} + +\subsection{Where} +\input{VL2_define_functions2.tex} + +\subsection{Let} +\input{VL2_define_functions3.tex} + +\subsection{Let vs Where} +\input{VL2_define_functions4.tex} + +\subsection{Anonymous functions} +\input{VL2_define_functions5.tex} + + +\section{Currying} + +\input{VL2_currying1.tex} +\\\\ +\input{VL2_currying2.tex} +\\\\ +\input{VL2_currying3.tex} +\\\\ +\input{VL2_currying4.tex} +\\\\ +\input{VL2_currying5.tex} +\\\\ +\input{VL2_currying6.tex} +\input{VL2_currying7.tex} +\input{VL2_currying8.tex} + +\section{Function composition} + +\input{VL2_composition1.tex} +\input{VL2_composition2.tex} +\input{VL2_composition3.tex} + + +\section{Recursion patterns} + +\input{VL2_rec_patterns1.tex} + +\subsection{Map} +\input{VL2_rec_patterns2.tex} +\input{VL2_rec_patterns3.tex} +\\\\ +\input{VL2_rec_patterns4.tex} +\\\\ +\input{VL2_rec_patterns5.tex} + +\subsection{Filter} +\input{VL2_rec_patterns6.tex} +\\\\ +\input{VL2_rec_patterns7.tex} + +\subsection{Fold} +\input{VL2_rec_patterns8.tex} +\input{VL2_rec_patterns9.tex} +\\\\ +\input{VL2_rec_patterns10.tex} +\input{VL2_rec_patterns11.tex} + +\subsection{Summary} +\input{VL2_rec_patterns12.tex} + + +\section{Reflection} + +\subsection{What you should know} +\input{VL2_reflection1.tex} + +\subsection{Questions for you} +\input{VL2_reflection2.tex} + +\section{References} + +\subsection{Links} +\input{VL_links.tex} + +\subsection{Sources} +\input{VL_sources.tex} + +\end{document} \ No newline at end of file diff --git a/VL2_polymorphism1.tex b/VL2_polymorphism1.tex new file mode 100644 index 0000000..d8c8bc3 --- /dev/null +++ b/VL2_polymorphism1.tex @@ -0,0 +1,20 @@ +So when we said that haskell is good for abstraction, what did we actually mean? Do we have something like java generics or C++ templates? +\vspace{\baselineskip} +\\ +\pause +Even better! Haskell supports polymorphism for both data types and functions.\\ +Let's start with a polymorphic data type: +\begin{haskellcode} +data List t = Empty | Cons t (List t) +\end{haskellcode} +So we just implemented our own singly-linked List. For any type! Let's use it: +\pause +\begin{haskellcode} +intList :: List Int +intList = Cons 3 (Cons 5 (Cons 2 Empty)) + +charList :: List Char +charList = Cons 'x' (Cons 'y' (Cons 'z' Empty)) + +-- whatever you can imagine goes here +\end{haskellcode} \ No newline at end of file diff --git a/VL2_polymorphism2.tex b/VL2_polymorphism2.tex new file mode 100644 index 0000000..65ab705 --- /dev/null +++ b/VL2_polymorphism2.tex @@ -0,0 +1,20 @@ +And now we are going to write functions to use it: +\begin{haskellcode} +isListEmpty :: List t -> Bool +isListEmpty Emtpy = True +isListEmpty x = False +\end{haskellcode} +\pause +We can even have more generic stuff like: +\begin{haskellcode} +f :: a -> b +\end{haskellcode} +Whatever the function does... it has something of one type and returns something of another type (it could be the same type, but doesn't need to). That's all we know. +\vspace{\baselineskip} +\\ +\pause +Similarly, remember the function \code{head} which gives us the first element of a list? The type signature actually looks like this: +\begin{haskellcode} +head :: [a] -> a +\end{haskellcode} +Makes sense? \ No newline at end of file diff --git a/VL2_polymorphism3.tex b/VL2_polymorphism3.tex new file mode 100644 index 0000000..e69de29 diff --git a/VL2_rec_patterns1.tex b/VL2_rec_patterns1.tex new file mode 100644 index 0000000..62682d6 --- /dev/null +++ b/VL2_rec_patterns1.tex @@ -0,0 +1,9 @@ +Since we use lists a lot in haskell, we also want some more powerful functions to deal with them. E.g.: +\begin{itemize} +\item perform an operation on every element on a list +\item keep only some elements in the list, following some criteria +\item "summarize" the elements of the list somehow +\item ... +\end{itemize} +\pause +How do we do that? \ No newline at end of file diff --git a/VL2_rec_patterns10.tex b/VL2_rec_patterns10.tex new file mode 100644 index 0000000..7aec343 --- /dev/null +++ b/VL2_rec_patterns10.tex @@ -0,0 +1,14 @@ +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} \ No newline at end of file diff --git a/VL2_rec_patterns11.tex b/VL2_rec_patterns11.tex new file mode 100644 index 0000000..739ea38 --- /dev/null +++ b/VL2_rec_patterns11.tex @@ -0,0 +1,21 @@ +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} \ No newline at end of file diff --git a/VL2_rec_patterns12.tex b/VL2_rec_patterns12.tex new file mode 100644 index 0000000..c8c1b5d --- /dev/null +++ b/VL2_rec_patterns12.tex @@ -0,0 +1,5 @@ +\begin{itemizep} +\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{itemizep} \ No newline at end of file diff --git a/VL2_rec_patterns2.tex b/VL2_rec_patterns2.tex new file mode 100644 index 0000000..5daef15 --- /dev/null +++ b/VL2_rec_patterns2.tex @@ -0,0 +1,7 @@ +Let's say we have a list of \code{Int} and want to add \code{2} to every element of the list. +\begin{haskellcode} +addTwo :: [Int] -> [Int] +addTwo ... ? +\end{haskellcode} +\pause +\textbf{Exercise:} Find the answer! 5 minutes time, remember the \emph{cons} operator \code{(:)}, pattern matching on lists and ofc recursion! Start with the case of an empty list. \ No newline at end of file diff --git a/VL2_rec_patterns3.tex b/VL2_rec_patterns3.tex new file mode 100644 index 0000000..3d24ead --- /dev/null +++ b/VL2_rec_patterns3.tex @@ -0,0 +1,23 @@ +Solution? +\begin{haskellcode} +addTwo :: [Int] -> [Int] +addTwo [] = [] +addTwo (x:xs) = (x + 2) : addTwo xs +\end{haskellcode} +\pause +Now we want to square every element: +\pause +\begin{haskellcode} +square :: [Int] -> [Int] +square [] = [] +square (x:xs) = (x * x) : square xs +\end{haskellcode} +\pause +Now we want the absolute of every element: +\begin{haskellcode} +absList :: [Int] -> [Int] +absList [] = [] +absList (x:xs) = (abs x) : absList xs +\end{haskellcode} +\pause +Do you notice something? \ No newline at end of file diff --git a/VL2_rec_patterns4.tex b/VL2_rec_patterns4.tex new file mode 100644 index 0000000..656a2bb --- /dev/null +++ b/VL2_rec_patterns4.tex @@ -0,0 +1,16 @@ +All those 3 functions look almost the same. Since haskell is about abstraction, we would never really write any of those like that. Instead, we will write a function that generalizes all 3. +\vspace{\baselineskip} +\\ +\pause +I'll give you the type signature, can you guess how the implementation looks like? +\begin{haskellcode} +map :: (a -> b) -> [a] -> [b] +\end{haskellcode} +Solution? +\pause +\begin{haskellcode} +map :: (a -> b) -> [a] -> [b] +map f [] = [] +map f (x:xs) = f x : map f xs +\end{haskellcode} +So we don't really know what the function \code{f} does, but we know that it converts one element of the list to something else. We \emph{map} a function over a list! Hence the name. \ No newline at end of file diff --git a/VL2_rec_patterns5.tex b/VL2_rec_patterns5.tex new file mode 100644 index 0000000..fcd4d9c --- /dev/null +++ b/VL2_rec_patterns5.tex @@ -0,0 +1,15 @@ +And now watch this: +\begin{haskellcode} +addTwo :: [Int] -> [Int] +addTwo xs = map (\x -> x + 2) xs + +square :: [Int] -> [Int] +square xs = map (\x -> x * x) xs + +absList :: [Int] -> [Int] +absList xs = map (\x -> abs x) xs +-- a haskeller would write, GHCi... +absList = map abs +\end{haskellcode} +\pause +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}). \ No newline at end of file diff --git a/VL2_rec_patterns6.tex b/VL2_rec_patterns6.tex new file mode 100644 index 0000000..77fb992 --- /dev/null +++ b/VL2_rec_patterns6.tex @@ -0,0 +1,23 @@ +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? \ No newline at end of file diff --git a/VL2_rec_patterns7.tex b/VL2_rec_patterns7.tex new file mode 100644 index 0000000..06dabdb --- /dev/null +++ b/VL2_rec_patterns7.tex @@ -0,0 +1,14 @@ +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. \ No newline at end of file diff --git a/VL2_rec_patterns8.tex b/VL2_rec_patterns8.tex new file mode 100644 index 0000000..ebaff36 --- /dev/null +++ b/VL2_rec_patterns8.tex @@ -0,0 +1,25 @@ +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} \ No newline at end of file diff --git a/VL2_rec_patterns9.tex b/VL2_rec_patterns9.tex new file mode 100644 index 0000000..1edc18a --- /dev/null +++ b/VL2_rec_patterns9.tex @@ -0,0 +1,19 @@ +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{itemizep} +\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{itemizep} +\slidep +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}. \ No newline at end of file diff --git a/VL2_reflection1.tex b/VL2_reflection1.tex new file mode 100644 index 0000000..fd54d2b --- /dev/null +++ b/VL2_reflection1.tex @@ -0,0 +1,7 @@ +\begin{itemize} +\item how to write polymorphic data types and functions +\item how you inline functions +\item what currying is and why we need it in haskell +\item how you compose functions +\item how to abstract out recursion patterns +\end{itemize} \ No newline at end of file diff --git a/VL2_reflection2.tex b/VL2_reflection2.tex new file mode 100644 index 0000000..1cfc269 --- /dev/null +++ b/VL2_reflection2.tex @@ -0,0 +1,9 @@ +\begin{itemize} +\item what is the difference between \code{let} and \code{where}? +\item what is the difference between \code{foldr} and \code{foldl}? +\item what is the difference between explicit and implicit recursion? Give examples +\item how many arguments does a haskell function have (strictly speaking)? +\item what do you have to keep in mind in order to make function composition work? +\item can you define map and filter in terms of foldr? +\item what is eta reduction (or: eta abstraction)? +\end{itemize} \ No newline at end of file diff --git a/VL2_reiteration.tex b/VL2_reiteration.tex new file mode 100644 index 0000000..cd2a84f --- /dev/null +++ b/VL2_reiteration.tex @@ -0,0 +1,6 @@ +\begin{itemize} +\item What is haskell? What are the 3 fundamental concepts behind it? +\item How do you do pattern matching? +\item What is the difference between lists and tuples? How do you construct them? +\item How do you define your own data types? +\end{itemize} \ No newline at end of file