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
|
||||
\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}
|
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