VL2: Restructure files, add proper article/handout version
This commit is contained in:
parent
fcbb846d7e
commit
86969074e3
557
VL2.tex
557
VL2.tex
@ -37,6 +37,10 @@
|
|||||||
|
|
||||||
% macros and environments
|
% macros and environments
|
||||||
\newcommand{\code}[1]{\texttt{#1}}
|
\newcommand{\code}[1]{\texttt{#1}}
|
||||||
|
\newcommand{\slidep}{\onslide<+->}
|
||||||
|
\newenvironment{itemizep}
|
||||||
|
{\begin{itemize}[<+->]}
|
||||||
|
{\end{itemize}}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
|
|
||||||
@ -56,12 +60,7 @@
|
|||||||
|
|
||||||
\begin{frame}
|
\begin{frame}
|
||||||
\frametitle{1. Reiteration (ctn.)}
|
\frametitle{1. Reiteration (ctn.)}
|
||||||
\begin{itemize}
|
\input{VL2_reiteration.tex}
|
||||||
\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}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\section{2. Polymorphism}
|
\section{2. Polymorphism}
|
||||||
@ -73,145 +72,52 @@
|
|||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{2. Polymorphism (ctn.)}
|
\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?
|
\input{VL2_polymorphism1.tex}
|
||||||
\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}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{2. Polymorphism (ctn.)}
|
\frametitle{2. Polymorphism (ctn.)}
|
||||||
And now we are going to write functions to use it:
|
\input{VL2_polymorphism2.tex}
|
||||||
\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?
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\section{3. More ways to define functions}
|
\section{3. More ways to define functions}
|
||||||
|
|
||||||
\begin{frame}
|
\begin{frame}
|
||||||
\frametitle{6. More ways to define functions}
|
\frametitle{3. More ways to define functions}
|
||||||
\tableofcontents[currentsection,hideothersubsections]
|
\tableofcontents[currentsection,hideothersubsections]
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{3. More ways to define functions (ctn.)}
|
\frametitle{3. More ways to define functions (ctn.)}
|
||||||
Now you know how a regular function looks like, e.g:
|
\input{VL2_define_functions1.tex}
|
||||||
\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.
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\subsection{3.1. Where}
|
\subsection{3.1. Where}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{3.1. Where}
|
\frametitle{3.1. Where}
|
||||||
We use \code{where} to define a helper function:
|
\input{VL2_define_functions2.tex}
|
||||||
\begin{haskellcode}
|
|
||||||
f :: Int -> Int
|
|
||||||
f x = x + (y 2)
|
|
||||||
where
|
|
||||||
y :: Int -> Int
|
|
||||||
y p = x + p
|
|
||||||
\end{haskellcode}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\subsection{3.2. Let}
|
\subsection{3.2. Let}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{3.2. Let}
|
\frametitle{3.2. Let}
|
||||||
Another way which is very similar would be using \code{let}:
|
\input{VL2_define_functions3.tex}
|
||||||
\begin{haskellcode}
|
|
||||||
f :: Int -> Int
|
|
||||||
f x = let y p = x + p
|
|
||||||
in x + (y 2)
|
|
||||||
\end{haskellcode}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\subsection{3.3. Let vs Where}
|
\subsection{3.3. Let vs Where}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{3.3. Let vs Where}
|
\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.:
|
\input{VL2_define_functions4.tex}
|
||||||
\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}?
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\subsection{3.4. Anonymous functions}
|
\subsection{3.4. Anonymous functions}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{3.4. Anonymous functions}
|
\frametitle{3.4. Anonymous functions}
|
||||||
We can also have \textbf{anonymous functions} which just means the function doesn't have a name:
|
\input{VL2_define_functions5.tex}
|
||||||
\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.
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\section{4. Currying}
|
\section{4. Currying}
|
||||||
@ -223,131 +129,42 @@ Anonymous functions will come extremely handy later, you'll see.
|
|||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{4. Currying (ctn.)}
|
\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:
|
\input{VL2_currying1.tex}
|
||||||
\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.
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{4. Currying (ctn.)}
|
\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.
|
\input{VL2_currying2.tex}
|
||||||
\vspace{\baselineskip}
|
|
||||||
\\
|
|
||||||
Let that sink in a little bit and read it again.
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{4. Currying (ctn.)}
|
\frametitle{4. Currying (ctn.)}
|
||||||
Maybe a mathematical example will make things clearer. Let's say we have the function:\\
|
\input{VL2_currying3.tex}
|
||||||
$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$
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{4. Currying (ctn.)}
|
\frametitle{4. Currying (ctn.)}
|
||||||
You can also imagine this geometrically:\\
|
\input{VL2_currying4.tex}
|
||||||
$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.
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{4. Currying (ctn.)}
|
\frametitle{4. Currying (ctn.)}
|
||||||
So in mathematical terms you can say:\\
|
\input{VL2_currying5.tex}
|
||||||
$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?
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{4. Currying (ctn.)}
|
\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:
|
\input{VL2_currying6.tex}
|
||||||
\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}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{4. Currying (ctn.)}
|
\frametitle{4. Currying (ctn.)}
|
||||||
As said in the beginning of this section, these two look pretty similar:
|
\input{VL2_currying7.tex}
|
||||||
\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}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{4. Currying (ctn.)}
|
\frametitle{4. Currying (ctn.)}
|
||||||
So... now that we know what currying is, let's summarize:
|
\input{VL2_currying8.tex}
|
||||||
\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}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\section{5. Function composition}
|
\section{5. Function composition}
|
||||||
@ -360,78 +177,17 @@ So... now that we know what currying is, let's summarize:
|
|||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{5. Function composition (ctn.)}
|
\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.
|
\input{VL2_composition1.tex}
|
||||||
\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}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{5. Function composition}
|
\frametitle{5. Function composition}
|
||||||
But let's not stop here. What does the dot \code{(.)} actually mean?
|
\input{VL2_composition2.tex}
|
||||||
\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}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{5. Function composition}
|
\frametitle{5. Function composition}
|
||||||
And now you can chain functions together. Not just two! Look:
|
\input{VL2_composition3.tex}
|
||||||
\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.
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\section{6. Recursion patterns}
|
\section{6. Recursion patterns}
|
||||||
@ -443,247 +199,68 @@ That sounds complicated at first, because it counts for the whole composition ch
|
|||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6. Recursion patterns (ctn.)}
|
\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.:
|
\input{VL2_rec_patterns1.tex}
|
||||||
\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?
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\subsection{6.1. map}
|
\subsection{6.1. Map}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6.1. map}
|
\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.
|
\input{VL2_rec_patterns2.tex}
|
||||||
\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.
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6.1. map (ctn.)}
|
\frametitle{6.1. Map (ctn.)}
|
||||||
Solution?
|
\input{VL2_rec_patterns3.tex}
|
||||||
\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?
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6.1. map (ctn.)}
|
\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.
|
\input{VL2_rec_patterns4.tex}
|
||||||
\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.
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6.1. map (ctn.)}
|
\frametitle{6.1. Map (ctn.)}
|
||||||
And now watch this:
|
\input{VL2_rec_patterns5.tex}
|
||||||
\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}).
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\subsection{6.2. filter}
|
\subsection{6.2. Filter}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6.2. filter}
|
\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:
|
\input{VL2_rec_patterns6.tex}
|
||||||
\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}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6.2. filter (ctn.)}
|
\frametitle{6.2. Filter (ctn.)}
|
||||||
Let's abstract out the common pieces! This will be our type signature:
|
\input{VL2_rec_patterns7.tex}
|
||||||
\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}
|
\end{frame}
|
||||||
|
|
||||||
\subsection{6.3. fold}
|
\subsection{6.3. Fold}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6.3. fold}
|
\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:
|
\input{VL2_rec_patterns8.tex}
|
||||||
\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}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6.3. fold (ctn.)}
|
\frametitle{6.3. Fold (ctn.)}
|
||||||
To cut the story short, the abstract solution looks like this:
|
\input{VL2_rec_patterns9.tex}
|
||||||
\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}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6.3. fold (ctn.)}
|
\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?
|
\input{VL2_rec_patterns10.tex}
|
||||||
\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}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6.3. fold (ctn.)}
|
\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}.\\
|
\input{VL2_rec_patterns11.tex}
|
||||||
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}
|
\end{frame}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{6.3. summary}
|
\frametitle{6.3. Summary}
|
||||||
\begin{itemize}[<+->]
|
\input{VL2_rec_patterns12.tex}
|
||||||
\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{frame}
|
||||||
|
|
||||||
\section{7. Reflection}
|
\section{7. Reflection}
|
||||||
@ -696,28 +273,14 @@ GHCi...
|
|||||||
|
|
||||||
\begin{frame}
|
\begin{frame}
|
||||||
\frametitle{7.1. What you should know now}
|
\frametitle{7.1. What you should know now}
|
||||||
\begin{itemize}
|
\input{VL2_reflection1.tex}
|
||||||
\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}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\subsection{7.2. Questions for you}
|
\subsection{7.2. Questions for you}
|
||||||
|
|
||||||
\begin{frame}[fragile]
|
\begin{frame}[fragile]
|
||||||
\frametitle{7.2. Questions for you}
|
\frametitle{7.2. Questions for you}
|
||||||
\begin{itemize}
|
\input{VL2_reflection2.tex}
|
||||||
\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}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\section{8. References}
|
\section{8. References}
|
||||||
@ -731,26 +294,14 @@ GHCi...
|
|||||||
|
|
||||||
\begin{frame}
|
\begin{frame}
|
||||||
\frametitle{8.1. Further reading and useful links}
|
\frametitle{8.1. Further reading and useful links}
|
||||||
\begin{itemize}
|
\input{VL_links.tex}
|
||||||
\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}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\subsection{8.2. Sources}
|
\subsection{8.2. Sources}
|
||||||
|
|
||||||
\begin{frame}
|
\begin{frame}
|
||||||
\frametitle{8.2. Sources}
|
\frametitle{8.2. Sources}
|
||||||
\begin{itemize}
|
\input{VL_sources.tex}
|
||||||
\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}
|
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
\end{document}
|
\end{document}
|
21
VL2_composition1.tex
Normal file
21
VL2_composition1.tex
Normal file
@ -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}
|
18
VL2_composition2.tex
Normal file
18
VL2_composition2.tex
Normal file
@ -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}
|
25
VL2_composition3.tex
Normal file
25
VL2_composition3.tex
Normal file
@ -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.
|
13
VL2_currying1.tex
Normal file
13
VL2_currying1.tex
Normal file
@ -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.
|
4
VL2_currying2.tex
Normal file
4
VL2_currying2.tex
Normal file
@ -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.
|
18
VL2_currying3.tex
Normal file
18
VL2_currying3.tex
Normal file
@ -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$
|
7
VL2_currying4.tex
Normal file
7
VL2_currying4.tex
Normal file
@ -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.
|
16
VL2_currying5.tex
Normal file
16
VL2_currying5.tex
Normal file
@ -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?
|
21
VL2_currying6.tex
Normal file
21
VL2_currying6.tex
Normal file
@ -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}
|
12
VL2_currying7.tex
Normal file
12
VL2_currying7.tex
Normal file
@ -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}
|
6
VL2_currying8.tex
Normal file
6
VL2_currying8.tex
Normal file
@ -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}
|
17
VL2_define_functions1.tex
Normal file
17
VL2_define_functions1.tex
Normal file
@ -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.
|
8
VL2_define_functions2.tex
Normal file
8
VL2_define_functions2.tex
Normal file
@ -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}
|
6
VL2_define_functions3.tex
Normal file
6
VL2_define_functions3.tex
Normal file
@ -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}
|
17
VL2_define_functions4.tex
Normal file
17
VL2_define_functions4.tex
Normal file
@ -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}?
|
12
VL2_define_functions5.tex
Normal file
12
VL2_define_functions5.tex
Normal file
@ -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.
|
147
VL2_handout.tex
Normal file
147
VL2_handout.tex
Normal file
@ -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}
|
20
VL2_polymorphism1.tex
Normal file
20
VL2_polymorphism1.tex
Normal file
@ -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}
|
20
VL2_polymorphism2.tex
Normal file
20
VL2_polymorphism2.tex
Normal file
@ -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?
|
0
VL2_polymorphism3.tex
Normal file
0
VL2_polymorphism3.tex
Normal file
9
VL2_rec_patterns1.tex
Normal file
9
VL2_rec_patterns1.tex
Normal file
@ -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?
|
14
VL2_rec_patterns10.tex
Normal file
14
VL2_rec_patterns10.tex
Normal file
@ -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}
|
21
VL2_rec_patterns11.tex
Normal file
21
VL2_rec_patterns11.tex
Normal file
@ -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}
|
5
VL2_rec_patterns12.tex
Normal file
5
VL2_rec_patterns12.tex
Normal file
@ -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}
|
7
VL2_rec_patterns2.tex
Normal file
7
VL2_rec_patterns2.tex
Normal file
@ -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.
|
23
VL2_rec_patterns3.tex
Normal file
23
VL2_rec_patterns3.tex
Normal file
@ -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?
|
16
VL2_rec_patterns4.tex
Normal file
16
VL2_rec_patterns4.tex
Normal file
@ -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.
|
15
VL2_rec_patterns5.tex
Normal file
15
VL2_rec_patterns5.tex
Normal file
@ -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}).
|
23
VL2_rec_patterns6.tex
Normal file
23
VL2_rec_patterns6.tex
Normal file
@ -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?
|
14
VL2_rec_patterns7.tex
Normal file
14
VL2_rec_patterns7.tex
Normal file
@ -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.
|
25
VL2_rec_patterns8.tex
Normal file
25
VL2_rec_patterns8.tex
Normal file
@ -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}
|
19
VL2_rec_patterns9.tex
Normal file
19
VL2_rec_patterns9.tex
Normal file
@ -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}.
|
7
VL2_reflection1.tex
Normal file
7
VL2_reflection1.tex
Normal file
@ -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}
|
9
VL2_reflection2.tex
Normal file
9
VL2_reflection2.tex
Normal file
@ -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}
|
6
VL2_reiteration.tex
Normal file
6
VL2_reiteration.tex
Normal file
@ -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}
|
Loading…
Reference in New Issue
Block a user