VL2: translate into german
This commit is contained in:
parent
19abcc037e
commit
f7eda19f1f
@ -5,14 +5,14 @@
|
|||||||
% title page information
|
% title page information
|
||||||
\author{Julian Ospald}
|
\author{Julian Ospald}
|
||||||
\institute{FH Bielefeld}
|
\institute{FH Bielefeld}
|
||||||
\title{Haskell: higher order functions}
|
\title{Haskell: \ifger{Funktionen höherer Ordnung}{higher order functions}}
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
|
|
||||||
\frame{\titlepage}
|
\frame{\titlepage}
|
||||||
|
|
||||||
\begin{frame}
|
\begin{frame}
|
||||||
\frametitle{Table of Contents}
|
\frametitle{\ifger{Inhaltsverzeichnis}{Table of Contents}}
|
||||||
\tableofcontents[hidesubsections=true]
|
\tableofcontents[hidesubsections=true]
|
||||||
\end{frame}
|
\end{frame}
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
\section{Reiteration}
|
\section{\ifger{Rückblick}{Reiteration}}
|
||||||
|
|
||||||
\slidetoc
|
\slidetoc
|
||||||
|
|
||||||
\slide{./content/VL2_reiteration.tex}
|
\slide{./content/VL2_reiteration.tex}
|
||||||
|
|
||||||
|
|
||||||
\section{Polymorphism}
|
\section{\ifger{Polymorphie}{Polymorphism}}
|
||||||
|
|
||||||
\slidetoc
|
\slidetoc
|
||||||
|
|
||||||
@ -13,7 +13,7 @@
|
|||||||
\slide{./content/VL2_polymorphism2.tex}[ (cnt.)]
|
\slide{./content/VL2_polymorphism2.tex}[ (cnt.)]
|
||||||
|
|
||||||
|
|
||||||
\section{More ways to define functions}
|
\section{\ifger{Andere Arten der Funktionsdefinition}{More ways to define functions}}
|
||||||
|
|
||||||
\slidetoc
|
\slidetoc
|
||||||
|
|
||||||
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
\slide{./content/VL2_let_vs_where.tex}
|
\slide{./content/VL2_let_vs_where.tex}
|
||||||
|
|
||||||
\subsection{Anonymous functions}
|
\subsection{\ifger{Anonyme Funktionen}{Anonymous functions}}
|
||||||
|
|
||||||
\slide{./content/VL2_anonymous_functions.tex}
|
\slide{./content/VL2_anonymous_functions.tex}
|
||||||
|
|
||||||
@ -45,26 +45,26 @@
|
|||||||
|
|
||||||
\slide{./content/VL2_currying2.tex}
|
\slide{./content/VL2_currying2.tex}
|
||||||
|
|
||||||
\subsection{Mathematical example}
|
\subsection{\ifger{Mathematisches Beispiel}{Mathematical example}}
|
||||||
\slide{./content/VL2_currying3.tex}
|
\slide{./content/VL2_currying3.tex}
|
||||||
|
|
||||||
\subsection{Geometrical example}
|
\subsection{\ifger{Geometrisches Beispiel}{Geometrical example}}
|
||||||
\slide{./content/VL2_currying4.tex}
|
\slide{./content/VL2_currying4.tex}
|
||||||
|
|
||||||
\subsection{Conclusion}
|
\subsection{\ifger{Schlussfolgerung}{Conclusion}}
|
||||||
\slide{./content/VL2_currying5.tex}
|
\slide{./content/VL2_currying5.tex}
|
||||||
|
|
||||||
\subsection{Partial application}
|
\subsection{Partial application}
|
||||||
\slide{./content/VL2_currying6.tex}
|
\slide{./content/VL2_currying6.tex}
|
||||||
|
|
||||||
\subsection{Curry and Uncurry}
|
\subsection{Curry \ifger{und}{and} Uncurry}
|
||||||
\slide{./content/VL2_currying7.tex}
|
\slide{./content/VL2_currying7.tex}
|
||||||
|
|
||||||
\subsection{Summary}
|
\subsection{\ifger{Zusammenfassung Currying}{Summary currying}}
|
||||||
\slide{./content/VL2_currying8.tex}
|
\slide{./content/VL2_currying8.tex}
|
||||||
|
|
||||||
|
|
||||||
\section{Function composition}
|
\section{\ifger{Funktionskomposition}{Function composition}}
|
||||||
|
|
||||||
\slidetoc
|
\slidetoc
|
||||||
|
|
||||||
@ -73,7 +73,7 @@
|
|||||||
\slide{./content/VL2_composition3.tex}[ (cnt.)]
|
\slide{./content/VL2_composition3.tex}[ (cnt.)]
|
||||||
|
|
||||||
|
|
||||||
\section{Recursion patterns}
|
\section{\ifger{Rekursionsstrukturen}{Recursion patterns}}
|
||||||
|
|
||||||
\slidetoc
|
\slidetoc
|
||||||
|
|
||||||
@ -99,22 +99,25 @@
|
|||||||
\slide{./content/VL2_fold2.tex}[ (cnt.)]
|
\slide{./content/VL2_fold2.tex}[ (cnt.)]
|
||||||
\slide{./content/VL2_fold3.tex}[ (cnt.)]
|
\slide{./content/VL2_fold3.tex}[ (cnt.)]
|
||||||
\slide{./content/VL2_fold4.tex}[ (cnt.)]
|
\slide{./content/VL2_fold4.tex}[ (cnt.)]
|
||||||
\slide{./content/VL2_fold5.tex}[ (cnt.)]
|
|
||||||
|
\subsection{\ifger{Zusammenfassung Rekurssionsstrukturen}{Summary recursion patterns}}
|
||||||
|
|
||||||
|
\slide{./content/VL2_fold5.tex}
|
||||||
|
|
||||||
|
|
||||||
\section{Reflection}
|
\section{\ifger{Reflexion}{Reflection}}
|
||||||
|
|
||||||
\slidetoc
|
\slidetoc
|
||||||
|
|
||||||
\subsection{What you should know}
|
\subsection{\ifger{Was Sie wissen sollten}{What you should know}}
|
||||||
|
|
||||||
\slide{./content/VL2_what_you_should_know.tex}
|
\slide{./content/VL2_what_you_should_know.tex}
|
||||||
|
|
||||||
\subsection{Questions for you}
|
\subsection{\ifger{Fragen an Sie}{Questions for you}}
|
||||||
|
|
||||||
\slide{./content/VL2_questions_for_you.tex}
|
\slide{./content/VL2_questions_for_you.tex}
|
||||||
|
|
||||||
\section{References}
|
\section{\ifger{Referenzen}{References}}
|
||||||
|
|
||||||
\slidetoc
|
\slidetoc
|
||||||
|
|
||||||
@ -122,6 +125,6 @@
|
|||||||
|
|
||||||
\slide{../common/content/VL_links.tex}
|
\slide{../common/content/VL_links.tex}
|
||||||
|
|
||||||
\subsection{Sources}
|
\subsection{\ifger{Quellen}{Sources}}
|
||||||
|
|
||||||
\slide{../common/content/VL_sources.tex}
|
\slide{../common/content/VL_sources.tex}
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
% title page information
|
% title page information
|
||||||
\author{Julian Ospald}
|
\author{Julian Ospald}
|
||||||
\title{Haskell: higher order functions}
|
\title{Haskell: \ifger{Funktionen höherer Ordnung}{higher order functions}}
|
||||||
|
|
||||||
\maketitle
|
\maketitle
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
We can also have \textbf{anonymous functions} which just means the function doesn't have a name:
|
\ifger{Wir können auch \textbf{anonyme Funktionen} haben, was eigentlich nur bedeutet, dass die Funktion keinen Namen hat:}{We can also have \textbf{anonymous functions} which just means the function doesn't have a name:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f :: Int -> Int
|
f :: Int -> Int
|
||||||
f x = (\y -> y + 1) x
|
f x = (\y -> y + 1) x
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
Although this is basically the same as:
|
\ifger{Wobei dies praktisch dasselbe ist wie:}{Although this is basically the same as:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f :: Int -> Int
|
f :: Int -> Int
|
||||||
f x = x + 1
|
f x = x + 1
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
Anonymous functions will come extremely handy later, you'll see.
|
\ifger{Anonyme Funktionen werden für uns später sehr nützlich sein.}{Anonymous functions will come extremely handy later, you'll see.}
|
@ -1,12 +1,12 @@
|
|||||||
So why did we just bother so long with explaining currying? It's because it's very important for \emph{function composition}. Which again is also one of the fundamental concepts of functional programming.
|
\ifger{Wieso haben wir uns so lange mit Currying aufgehalten? Nun, es ist wie gesagt sehr wichtig für \emph{Funktionskomposition}. Sie zählt ebenfalls zu den fundamentalen Basiskonzepten der funktionalen Programmierung.}{So why did we just bother so long with explaining currying? It's because it's very important for \emph{function composition}. Which again is also one of the fundamental concepts of functional programming.}
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
From maths we already know that:\\
|
\ifger{Aus der Mathematik wissen wir bereits, dass:}{From maths we already know that:}\\
|
||||||
$(g \circ f)(x) = g(f(x))$
|
$(g \circ f)(x) = g(f(x))$
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\pause
|
\pause
|
||||||
And that's basically it. We do the same in haskell, it looks like this:
|
\ifger{Und das ist praktisch schon alles. Wir machen dasselbe in Haskell:}{And that's basically it. We do the same in haskell, it looks like this:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
composedFunction x = (f . g) x
|
composedFunction x = (f . g) x
|
||||||
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
But let's not stop here. What does the dot \hinline{(.)} actually mean?
|
\ifger{Aber das soll uns nicht genug sein. Was bedeutet dieser Punkt \hinline{(.)} tatsächlich?}{But let's not stop here. What does the dot \hinline{(.)} actually mean?}
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\pause
|
\pause
|
||||||
It's just a function (the \emph{prefix} version of \hinline{.})! Here is the type signature:
|
\ifger{Es ist einfach nur eine Funktion (die \emph{Prefix} Variante von \hinline{.})!}{It's just a function (the \emph{prefix} version of \hinline{.})! Here is the type signature:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
(.) :: (b -> c) -> (a -> b) -> a -> c
|
(.) :: (b -> c) -> (a -> b) -> a -> c
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
\textbf{Exercise:} Implement it! It's really just one line! Remember the mathematical definition.
|
\textbf{\ifger{Aufgabe:}{Exercise:}} \ifger{Implementiert es! Es ist tatsächlich nur eine Zeile. Erinnert Euch an die mathematische Definition.}{Implement it! It's really just one line! Remember the mathematical definition.}
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\pause
|
\pause
|
||||||
Solution:
|
\ifger{Lösung:}{Solution:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
(.) :: (b -> c) -> (a -> b) -> a -> c
|
(.) :: (b -> c) -> (a -> b) -> a -> c
|
||||||
(.) f g x = f (g x)
|
(.) f g x = f (g x)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
And now you can chain functions together. Not just two! Look:
|
\ifger{Und jetzt können wir Funktionen verketten, egal wieviele:}{And now you can chain functions together. Not just two! Look:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f :: String -> Bool
|
f :: String -> Bool
|
||||||
f xs = (even . length . (\x -> x ++ "Hello world")) xs
|
f xs = (even . length . (\x -> x ++ "Hello world")) xs
|
||||||
@ -7,7 +7,7 @@ f xs = even . length . (\x -> x ++ "Hello world") $ xs
|
|||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
% $
|
% $
|
||||||
\pause
|
\pause
|
||||||
Another example where currying is actually important:
|
\ifger{Ein anderes Beispiel, bei dem Currying tatsächlich relevant ist:}{Another example where currying is actually important:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f :: Int -> Bool
|
f :: Int -> Bool
|
||||||
f x = even . (+) 3 . (-) 4 $ x
|
f x = even . (+) 3 . (-) 4 $ x
|
||||||
@ -17,9 +17,9 @@ f x = even . (+) 3 . (-) $ 4 x
|
|||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
%$
|
%$
|
||||||
\pause
|
\pause
|
||||||
So there are a few things that we have to be aware of:
|
\ifger{Aber es gilt hier einige wichtige Dinge zu beachten:}{So there are a few things that we have to be aware of:}
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item the types have to fit!
|
\item \ifger{die Typen müssen passen!}{the types have to fit!}
|
||||||
\item the arity has to fit!
|
\item \ifger{die Arität muss passen!}{the arity has to fit!}
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
That sounds complicated at first, because it counts for the whole composition chain. But you'll get used to it.
|
\ifger{Das klingt anfangs kompliziert, weil es für die gesamte Verkettung gilt, aber man kommt sehr schnell rein.}{That sounds complicated at first, because it counts for the whole composition chain. But you'll get used to it.}
|
@ -1,13 +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:
|
\ifger{Dies ist, was aus Haskell eine so wunderbare funktionale Sprache macht. In der letzten Vorlesung habe ich bewusst vermieden Funktionen mit mehreren Argumenten zu zeigen. Das liegt daran, dass wir ein bisschen weiter ausholen müssen für das, was jetzt kommt:}{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
|
\pause
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
addInt :: Int -> Int -> Int
|
addInt :: Int -> Int -> Int
|
||||||
addInt x y = x + y
|
addInt x y = x + y
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
So, what is happening here? You probably expected something like:
|
\ifger{Was ist hier passiert? Eher hätte man vermutlich sowas erwartet:}{So, what is happening here? You probably expected something like:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
addInt :: (Int, Int) -> Int
|
addInt :: (Int, Int) -> Int
|
||||||
addInt (x, y) = x + y
|
addInt (x, y) = x + y
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
which is actually pretty close.
|
\ifger{was im Grunde der Sache sogar recht nahe kommt.}{which is actually pretty close.}
|
@ -1,4 +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.
|
\ifger{Currying ist eigentlich eine mathematische Sache und ist auf wikipedia wie folgt definiert: }{Currying is sort of a mathematical thing and is defined on wikipedia as:} \\''Currying 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.'' -- Wikipedia
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
Let that sink in a little bit and read it again.
|
\ifger{Darüber müssen wir erstmal nachdenken.}{Let that sink in a little bit and read it again.}
|
@ -1,18 +1,18 @@
|
|||||||
Maybe a mathematical example will make things clearer. Let's say we have the function:\\
|
\ifger{Vielleicht hilft ein mathematisches Beispiel die Dinge klarer zu machen. Wir haben z.b. folgende Funktion:}{Maybe a mathematical example will make things clearer. Let's say we have the function:}\\
|
||||||
$f(x, y) = y / x$
|
$f(x, y) = y / x$
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\pause
|
\pause
|
||||||
In order to evaluate the function for $x = 2$ and $y = 3$ we would do:\\
|
\ifger{Um diese Funktion für $x = 2$ und $y = 3$ zu berechnen würden wir einfach einsetzen:}{In order to evaluate the function for $x = 2$ and $y = 3$ we would do:}\\
|
||||||
$f(2, 3) = 2 / 3$\\
|
$f(2, 3) = 2 / 3$\\
|
||||||
and be done.
|
\ifger{und fertig sein.}{and be done.}
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\pause
|
\pause
|
||||||
However, how about we just put in x first and make a new function. Since x is gone, we can write:\\
|
\ifger{Allerdings, wie wäre es wenn wir nur für $x$ einsetzen und dadurch eine neue Funktion definieren. Da $x$ weg ist, können wir schreiben:}{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$
|
$g(y) = f(2, y) = y / 2$
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\pause
|
\pause
|
||||||
And in a second step we solve the function $g(y)$:\\
|
\ifger{Und erst in einem zweiten Schritt lösen wir die Gleichung indem wir $y$ in $g(y)$ einsetzen:}{And in a second step we solve the function $g(y)$:}\\
|
||||||
$g(3) = f (2, 3) = 3 / 2$
|
$g(3) = f (2, 3) = 3 / 2$
|
@ -1,7 +1,7 @@
|
|||||||
You can also imagine this geometrically:\\
|
\ifger{Wir können uns das ganze auch geometrisch vorstellen:}{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$.
|
$z = f(x, y)$ \ifger{ist}{is} 3-dimensional. \ifger{Wenn wir für die Variable $x$ einsetzen bekommen wir im Grunde eine 2-dimensionale Funktion (die Schnittebene). Wenn wir dann für $y$ einsetzen, bekommen wir den eigentlich Punkt $z$.}{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}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\includegraphics*[scale=0.4]{./images/Grafico_3d_x2+xy+y2.png}
|
\includegraphics*[scale=0.4]{./images/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.
|
\ifger{Für jeden dieser Schritte können wir eine echte neue Funktion definieren. Das funktioniert mit einer beliebigen Anzahl von Dimensionen/Argumenten.}{For every of these steps we can define a real new function. This scales up to any number of dimensions/arguments.}
|
@ -1,14 +1,14 @@
|
|||||||
So in mathematical terms you can say:\\
|
\ifger{D.h. mathematisch gesehen können wir schreiben:}{So in mathematical terms you can say:}\\
|
||||||
$f : A_1 \times ... \times A_n \mapsto B$
|
$f : A_1 \times ... \times A_n \mapsto B$
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
gets modified into:\\
|
\ifger{wird zu}{gets modified into:}\\
|
||||||
\pause
|
\pause
|
||||||
$f' : A_1 \mapsto (A_2 \mapsto (\ ...\ (A_n \mapsto B)))$
|
$f' : A_1 \mapsto (A_2 \mapsto (\ ...\ (A_n \mapsto B)))$
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\pause
|
\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:
|
\ifger{Die Klammern hier sind äußerst wichtig! Currying ist \emph{rechts}-assoziativ, d.h. die folgenden 2 Typsignaturen in Haskell sind äquivalent:}{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}
|
\begin{haskellcode}
|
||||||
f :: Int -> Int -> Int
|
f :: Int -> Int -> Int
|
||||||
f :: Int -> (Int -> Int)
|
f :: Int -> (Int -> Int)
|
||||||
@ -16,4 +16,4 @@ f :: Int -> (Int -> Int)
|
|||||||
-- but this is NOT the same
|
-- but this is NOT the same
|
||||||
f :: (Int -> Int) -> Int
|
f :: (Int -> Int) -> Int
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
On the other hand function application is \emph{left}-associative, so \hinline{f 3 2} is just a shorthand of \hinline{(f 3) 2}. Makes sense?
|
\ifger{Auf der anderen Seite ist Funktionsanwendung \emph{links}-assoziativ, d.h.}{On the other hand function application is \emph{left}-associative, so} \hinline{f 3 2} \ifger{ist nur die Kurzform für}{is just a shorthand of} \hinline{(f 3) 2}. \ifger{Macht Sinn?}{Makes sense?}
|
@ -1,4 +1,4 @@
|
|||||||
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:
|
\ifger{Was bedeutet das für uns? Es ermöglicht uns \textbf{partial application}, was bedeutet, dass wir einer Funktion nicht alle Argumente übergeben müssen. Wenn wir ''zu wenig'' Argumente übergeben, wird einfach eine neue Funktion generiert. Z.b. so:}{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
|
\pause
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
addInt :: Int -> Int -> Int
|
addInt :: Int -> Int -> Int
|
||||||
@ -7,13 +7,13 @@ addInt x y = x + y
|
|||||||
addTwo :: Int -> Int
|
addTwo :: Int -> Int
|
||||||
addTwo = addInt 2
|
addTwo = addInt 2
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
You probably noticed that we did not write \hinline{addTwo x = ...}, but why would we? We gave \hinline{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.
|
\ifger{Warum haben wir nicht \hinline{addTwo x = ...} geschrieben? Wieso sollten wir? Wir haben \hinline{addInt} ein Argument übergeben, also ist die Arität (im Beispiel vorher Dimension) einer weniger und damit ist noch ein Argument notwendig um den endgültigen Wert zu bekommen.}{You probably noticed that we did not write \hinline{addTwo x = ...}, but why would we? We gave \hinline{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.}
|
||||||
\pause
|
\pause
|
||||||
The reason we can omit the \hinline{x} here is that
|
\ifger{Der Grund warum wir \hinline{x} auslassen können ist, dass}{The reason we can omit the \hinline{x} here is that}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f x y z = ...
|
f x y z = ...
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
is just syntax sugar for
|
\ifger{nur syntax sugar ist für}{is just syntax sugar for}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f = \x -> (\y -> (\z -> ... )) -- right-associative, ofc
|
f = \x -> (\y -> (\z -> ... )) -- right-associative, ofc
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
@ -1,10 +1,10 @@
|
|||||||
As said in the beginning of this section, these two look pretty similar:
|
\ifger{Wie am Anfang dieses Kapitels bereits gesagts sind diese beiden Funktionen sehr ähnlich:}{As said in the beginning of this section, these two look pretty similar:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f :: Int -> Int -> Int
|
f :: Int -> Int -> Int
|
||||||
|
|
||||||
f :: (Int, Int) -> Int
|
f :: (Int, Int) -> Int
|
||||||
\end{haskellcode}
|
\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:
|
\ifger{Da wir jetzt wissen, dass man von der einen Form in die andere und zurück konvertieren kann, müssten wir dann nicht auch Funktionen dafür haben? Haben wir:}{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}
|
\begin{haskellcode}
|
||||||
curry :: ((a, b) -> c) -> a -> b -> c
|
curry :: ((a, b) -> c) -> a -> b -> c
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
So... now that we know what currying is, let's summarize:
|
\ifger{Zusammenfassend lässt sich über Currying sagen:}{So... now that we know what currying is, let's summarize:}
|
||||||
\begin{itemizep}
|
\begin{itemizep}
|
||||||
\item all functions in haskell have only one argument (strictly speaking)
|
\item \ifger{alle Funktionen in Haskell haben nur ein Argument (streng genommen)}{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 \ifger{wenn eine Funktion scheinbar mehrere Argumente hat steckt immer Currying dahinter um die Funktion zu evaluieren}{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)
|
\item \ifger{Currying erlaubt uns auch \emph{partial function application} (was auch sehr wichtig für Funktionskomposition ist)}{currying also allows us to do partial function application (which is important for function composition)}
|
||||||
\end{itemizep}
|
\end{itemizep}
|
@ -1,8 +1,8 @@
|
|||||||
Imagine we want to filter all even numbers of a list and throw away all others. I'll give you the type signature:
|
\ifger{Stellen wir uns vor wir wollen alle geraden Zahlen einer Liste und alle anderen nicht. Hier wäre die Typsignatur:}{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}
|
\begin{haskellcode}
|
||||||
filterEven :: [Int] -> [Int]
|
filterEven :: [Int] -> [Int]
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
Solution?
|
\ifger{Lösung?}{Solution?}
|
||||||
\pause
|
\pause
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
filterEven :: [Int] -> [Int]
|
filterEven :: [Int] -> [Int]
|
||||||
@ -12,7 +12,7 @@ filterEven (x:xs)
|
|||||||
| otherwise = filterEven xs
|
| otherwise = filterEven xs
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
Or: filter out all 0's, so we can count them later:
|
\ifger{Oder: wir filtern alle $0$en, damit wir sie später zählen können:}{Or: filter out all $0$'s, so we can count them later:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
filterZero :: [Int] -> [Int]
|
filterZero :: [Int] -> [Int]
|
||||||
filterZero [] = []
|
filterZero [] = []
|
||||||
@ -20,4 +20,4 @@ filterZero (x:xs)
|
|||||||
| x == 0 = x : filterZero xs
|
| x == 0 = x : filterZero xs
|
||||||
| otherwise = filterZero xs
|
| otherwise = filterZero xs
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
Again: do you notice something?
|
\ifger{Erneut: Fällt etwas auf?}{Again: do you notice something?}
|
@ -1,8 +1,8 @@
|
|||||||
Let's abstract out the common pieces! This will be our type signature:
|
\ifger{Wir werden die Rekursionsstruktur erneut herausabstrahieren! Die Typsignatur sieht so aus:}{Let's abstract out the common pieces! This will be our type signature:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
filter :: (a -> Bool) -> [a] -> [a]
|
filter :: (a -> Bool) -> [a] -> [a]
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
Solution?
|
\ifger{Lösung?}{Solution?}
|
||||||
\pause
|
\pause
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
filter :: (a -> Bool) -> [a] -> [a]
|
filter :: (a -> Bool) -> [a] -> [a]
|
||||||
@ -11,4 +11,4 @@ filter f (x:xs)
|
|||||||
| f x = x : filter f xs
|
| f x = x : filter f xs
|
||||||
| otherwise = filter f xs
|
| otherwise = filter f xs
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
Again: this function is part of the \emph{Prelude} as well.
|
\ifger{Diese Funktion ist ebenfalls Teil von \emph{Prelude}.}{Again: this function is part of the \emph{Prelude} as well.}
|
@ -1,8 +1,8 @@
|
|||||||
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:
|
\ifger{Es gibt noch eine weitere sehr wichtige Rekursionsstruktur. Stellen wir uns vor wir wollen alle Zahlen einer Liste aufsummieren. Die Typsignatur sieht wie folgt aus:}{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}
|
\begin{haskellcode}
|
||||||
sum :: [Int] -> Int
|
sum :: [Int] -> Int
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
Solution?
|
\ifger{Lösung?}{Solution?}
|
||||||
\pause
|
\pause
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
sum :: [Int] -> Int
|
sum :: [Int] -> Int
|
||||||
@ -10,14 +10,14 @@ sum [] = 0
|
|||||||
sum (x:xs) = x + sum xs
|
sum (x:xs) = x + sum xs
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
Or the product:
|
\ifger{Oder das Produkt:}{Or the product:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
prod :: [Int] -> Int
|
prod :: [Int] -> Int
|
||||||
prod [] = 1
|
prod [] = 1
|
||||||
prod (x:xs) = x * prod xs
|
prod (x:xs) = x * prod xs
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
Or the length:
|
\ifger{Oder die Länge:}{Or the length:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
length :: [a] -> Int
|
length :: [a] -> Int
|
||||||
length [] = 0
|
length [] = 0
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
To cut the story short, the abstract solution looks like this:
|
\ifger{Um es kurz zu machen, die abstrakte Lösung ist:}{To cut the story short, the abstract solution looks like this:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
fold :: b -> (a -> b -> b) -> [a] -> b
|
fold :: b -> (a -> b -> b) -> [a] -> b
|
||||||
fold z f [] = z
|
fold z f [] = z
|
||||||
fold z f (x:xs) = x `f` (fold z f xs)
|
fold z f (x:xs) = x `f` (fold z f xs)
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
Whoa! What's going on here?\\
|
Whoa! What's going on here?\\
|
||||||
Let's see...
|
\ifger{Schauen wir genauer hin...}{Let's see...}
|
||||||
\begin{itemizep}
|
\begin{itemizep}
|
||||||
\item \hinline{z} is what we return if the list is empty
|
\item \hinline{z} \ifger{ist was die Funktion zurückgibt, wenn die Liste leer ist}{is what we return if the list is empty}
|
||||||
\item \hinline{f} is our function (e.g. \hinline{(*)} or \hinline{(+)})
|
\item \hinline{f} \ifger{ist unsere Funktion}{is our function} (\ifger{z.b.}{e.g.} \hinline{(*)} \ifger{oder}{or} \hinline{(+)})
|
||||||
\item and the last remaining argument is the actual list we are working on
|
\item \ifger{das letzte Argument ist die eigentliche Liste, auf der wir arbeiten}{and the last remaining argument is the actual list we are working on}
|
||||||
\end{itemizep}
|
\end{itemizep}
|
||||||
\slidep
|
\slidep
|
||||||
The function application has the following form:\\
|
\ifger{Die Funktionsanwendung hat die folgende Form:}{The function application has the following form:}\\
|
||||||
\hinline{fold f z [a,b,c] == a `f` (b `f` (c `f` z))}
|
\hinline{fold f z [a,b,c] == a `f` (b `f` (c `f` z))}
|
||||||
\vspace{\baselineskip}
|
\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}.
|
\ifger{D.h. hier falten wir von rechts. \emph{Prelude} definiert diese Funktion bereits, die fast genauso ist wie unsere. Sie heisst \textbf{foldr}.}{This folds from the right, so the \emph{Prelude} already defines a function which is very similar to ours and called \textbf{foldr}.}
|
@ -1,4 +1,4 @@
|
|||||||
So how do our \hinline{sum}, \hinline{prod} and \hinline{length} functions look like if we use our \hinline{fold} abstraction?
|
\ifger{Jetzt wollen wir uns unsere Funktionen}{So how do our} \hinline{sum}, \hinline{prod} \ifger{und}{and} \hinline{length} \ifger{anschauen, wenn wir sie mittels \hinline{fold} implementieren:}{functions look like if we use our \hinline{fold} abstraction?}
|
||||||
\pause
|
\pause
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
sum :: [Int] -> Int
|
sum :: [Int] -> Int
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
There is also a function that folds from the \emph{left} which is also in the \emph{Prelude} and called \textbf{foldl}.\\
|
\ifger{Es gibt auch eine Funktion die von \emph{links} faltet und ebenfalls in \emph{Prelude} ist. Sie heisst \textbf{foldl}.}{There is also a function that folds from the \emph{left} which is also in the \emph{Prelude} and called \textbf{foldl}.}\\
|
||||||
To summarize:
|
\ifger{Zusammenfassend:}{To summarize:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
foldr f z [a,b,c] == a `f` (b `f` (c `f` z))
|
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
|
foldl f z [a,b,c] == ((z `f` a) `f` b) `f` c
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
For \hinline{foldl} the \hinline{z} is sort of the starting value.
|
\ifger{Für}{For} \hinline{foldl} \ifger{ist}{the} \hinline{z} \ifger{quasi der Startwert.}{is sort of the starting value.}
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\pause
|
\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/}
|
\ifger{Wir können sogar foldl mittels foldr ausdrücken und umgekehrt. Wer interessiert daran ist, sollte hier\footnote{\url{http://lambda.jstolarek.com/2012/07/expressing-foldl-in-terms-of-foldr}} weiterlesen.}{We can even express foldl in terms of foldr and vice versa. If you are interested, have a look here\footnote{\url{http://lambda.jstolarek.com/2012/07/expressing-foldl-in-terms-of-foldr}}.}
|
||||||
\vspace{\baselineskip}
|
\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}
|
\ifger{Es macht Sinn diese Funktionen in \emph{Prelude}\footnote{\url{https://hackage.haskell.org/package/base-4.8.0.0/docs/Prelude.html}} anzuschauen und ein bisschen damit herumzuspielen:}{You should definitely look them up in the \emph{Prelude}\footnote{\url{https://hackage.haskell.org/package/base-4.8.0.0/docs/Prelude.html}} and play with them:}
|
||||||
\begin{haskellcode*}{bgcolor=mygrey,frame=single,numbers=none,label=GHCi}
|
\begin{haskellcode*}{bgcolor=mygrey,frame=single,numbers=none,label=GHCi}
|
||||||
> foldr (-) 0 [1, 2, 3]
|
> foldr (-) 0 [1, 2, 3]
|
||||||
> foldl (-) 0 [1, 2, 3]
|
> foldl (-) 0 [1, 2, 3]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
\begin{itemizep}
|
\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 \ifger{Wenn wir wiederkehrende Strukturen in unserem Code finden abstrahieren wir sie heraus! Erfahrene Haskeller vermeiden explizite Rekursion, es sei denn die Rekursionsstruktur ist sehr komplex/spezifisch, sodass Abstraktion wenig Sinn macht.}{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 map, filter, fold etc \ifger{hängen alle vom Datentyp ab (hier: Liste)! Für neue Datentypen (z.b. einen Tree) können und werden wir unsere eigenen Rekursionsabstraktionen schreiben}{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
|
\item \ifger{diese Funktionen sind jedoch so fundamental, dass sie für die meisten Datentypen schon implementiert sind}{although these functions are so fundamental that they are already implemented for most data types out there}
|
||||||
\end{itemizep}
|
\end{itemizep}
|
@ -1,4 +1,4 @@
|
|||||||
Another way which is very similar would be using \hinline{let}:
|
\ifger{Ein ähnlicher Weg wäre über}{Another way which is very similar would be using} \hinline{let}:
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f :: Int -> Int
|
f :: Int -> Int
|
||||||
f x = let y p = x + p
|
f x = let y p = x + p
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
These look almost the same, but they are different constructs. \hinline{where} is bound to the pattern matching \hinline{f x =} and may also have access to parts of a function that are not syntactically expressions, e.g.:
|
\ifger{Sie ähneln sich stark, aber sind unterschiedliche Konstrukte.}{These look almost the same, but they are different constructs.} \hinline{where} \ifger{ist an das pattern matching (hier \hinline{f x ...=}) der Funktion gebunden und hat auch Zugriff auf Funktionsteile, die nicht syntaktische Ausdrücke sind, z.b.:}{is bound to the pattern matching \hinline{f x ...=} and may also have access to parts of a function that are not syntactically expressions, e.g.:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f x
|
f x
|
||||||
| cond1 x = a
|
| cond1 x = a
|
||||||
@ -7,11 +7,9 @@ f x
|
|||||||
where
|
where
|
||||||
a = w x
|
a = w x
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
While that is not possible with \hinline{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).
|
\ifger{während dies mit \hinline{let} so nicht möglich ist. Dieses ist hingegen ein echter Ausdruck und kann überall dort benutzt werden, wo Ausdrücke erlaubt sind (z.b. innerhalb von \emph{Monaden}, dazu später mehr).}{While that is not possible with \hinline{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}
|
\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}
|
\ifger{Es gibt hier noch ein paar weitere Feinheiten\footnote{\url{https://wiki.haskell.org/Let_vs._Where}}, aber generell ist es einfach nur Geschmackssache.}{There are a few more intricacies\footnote{\url{https://wiki.haskell.org/Let_vs._Where}}, but most of the time this is just style consideration.}
|
||||||
\pause
|
\pause
|
||||||
\vspace{\baselineskip}
|
\ifger{Wie müssten wir die Funktion umschreiben um \hinline{let} zu benutzen?}{How would we have to rewrite the function in order to use \hinline{let}?}
|
||||||
\\
|
|
||||||
How would we have to rewrite the function in order to use \hinline{let}?
|
|
@ -1,7 +1,7 @@
|
|||||||
Let's say we have a list of \hinline{Int} and want to add \hinline{2} to every element of the list.
|
\ifger{Stellen wir uns vor wir haben eine Liste von \hinline{Int} und wollen zu jedem Element \hinline{2} addieren.}{Let's say we have a list of \hinline{Int} and want to add \hinline{2} to every element of the list.}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
addTwo :: [Int] -> [Int]
|
addTwo :: [Int] -> [Int]
|
||||||
addTwo ... ?
|
addTwo ... ?
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
\textbf{Exercise:} Find the answer! 5 minutes time, remember the \emph{cons} operator \hinline{(:)}, pattern matching on lists and ofc recursion! Start with the case of an empty list.
|
\textbf{\ifger{Aufgabe:}{Exercise:}} \ifger{Lösung? 5 Minuten Zeit! Nützlich könnte sein: der \emph{cons} Operator \hinline{(:)}, pattern matching und natürlich Rekursion. Startet am besten mit dem Fall einer leeren Liste.}{Find the answer! 5 minutes time, remember the \emph{cons} operator \hinline{(:)}, pattern matching on lists and ofc recursion! Start with the case of an empty list.}
|
@ -1,11 +1,11 @@
|
|||||||
Solution?
|
\ifger{Lösung:}{Solution:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
addTwo :: [Int] -> [Int]
|
addTwo :: [Int] -> [Int]
|
||||||
addTwo [] = []
|
addTwo [] = []
|
||||||
addTwo (x:xs) = (x + 2) : addTwo xs
|
addTwo (x:xs) = (x + 2) : addTwo xs
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
Now we want to square every element:
|
\ifger{Jetzt wollen wir jedes Element quadrieren:}{Now we want to square every element:}
|
||||||
\pause
|
\pause
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
square :: [Int] -> [Int]
|
square :: [Int] -> [Int]
|
||||||
@ -13,11 +13,11 @@ square [] = []
|
|||||||
square (x:xs) = (x * x) : square xs
|
square (x:xs) = (x * x) : square xs
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
Now we want the absolute of every element:
|
\ifger{Jetzt wollen wir den Betrag jedes Elements:}{Now we want the absolute of every element:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
absList :: [Int] -> [Int]
|
absList :: [Int] -> [Int]
|
||||||
absList [] = []
|
absList [] = []
|
||||||
absList (x:xs) = (abs x) : absList xs
|
absList (x:xs) = (abs x) : absList xs
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
Do you notice something?
|
\ifger{Fällt etwas auf?}{Do you notice something?}
|
@ -1,16 +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.
|
\ifger{Alle 3 Funktionen sind sehr ähnlich. In Haskell wollen wir vor allem abstrahieren und würden niemals die Funktionen derart schreiben. Stattdessen werden wir eine Funktion schreiben, die die Rekursionsstruktur aller 3 abstrakt zusammenfässt.}{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}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\pause
|
\pause
|
||||||
I'll give you the type signature, can you guess how the implementation looks like?
|
\ifger{Ich gebe als Tipp die Typsignatur. Wie könnte die Implementierung aussehen?}{I'll give you the type signature, can you guess how the implementation looks like?}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
map :: (a -> b) -> [a] -> [b]
|
map :: (a -> b) -> [a] -> [b]
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
Solution?
|
\ifger{Lösung?}{Solution?}
|
||||||
\pause
|
\pause
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
map :: (a -> b) -> [a] -> [b]
|
map :: (a -> b) -> [a] -> [b]
|
||||||
map f [] = []
|
map f [] = []
|
||||||
map f (x:xs) = f x : map f xs
|
map f (x:xs) = f x : map f xs
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
So we don't really know what the function \hinline{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.
|
\ifger{Wir wissen nicht was die Funktion \hinline{f} genau macht, aber wir wissen, dass sie ein Element der Liste zu etwas anderem konvertiert. Wir \emph{mappen} eine Funktion über eine Liste! Daher der Name.}{So we don't really know what the function \hinline{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.}
|
@ -1,4 +1,4 @@
|
|||||||
And now watch this:
|
\ifger{Und jetzt definieren wir unsere ursprünglichen Funktionen mithilfe von \hinline{map}:}{And now watch this:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
addTwo :: [Int] -> [Int]
|
addTwo :: [Int] -> [Int]
|
||||||
addTwo xs = map (\x -> x + 2) xs
|
addTwo xs = map (\x -> x + 2) xs
|
||||||
@ -12,4 +12,4 @@ absList xs = map (\x -> abs x) xs
|
|||||||
absList = map abs
|
absList = map abs
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
Cool, right? So now we have abstracted out the \textbf{recursion pattern} that is all the same for those 3 functions. \hinline{map} is actually part of the standard library (called \emph{Prelude}).
|
\ifger{Cool, oder? Wir haben jetzt die \textbf{Rekursionsstruktur} herausabstrahiert, weil sie für alle 3 Funktionen dieselbe ist. \hinline{map} ist schon Teil des Standardmoduls \emph{Prelude}.}{Cool, right? So now we have abstracted out the \textbf{recursion pattern} that is all the same for those 3 functions. \hinline{map} is actually part of the standard library (called \emph{Prelude}).}
|
@ -1,17 +1,17 @@
|
|||||||
Now you know how a regular function looks like, e.g:
|
\ifger{Jetzt wissen wir wie reguläre Funktionen aussehen, z.b.:}{Now you know how a regular function looks like, e.g:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f :: Int -> Int
|
f :: Int -> Int
|
||||||
f x = x + 1
|
f x = x + 1
|
||||||
\end{haskellcode}
|
\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 \cinline{static}.
|
\ifger{Aber stellen wir uns vor, dass wir einige Hilfsfunktionen benötigen, die sehr spezifisch ist und eigentlich zur aktuellen Funktion gehört. In C würden wir diese vermutlich top-level deklarieren und \cinline{static} machen.}{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 \cinline{static}.}
|
||||||
\pause
|
\pause
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
Haskell allows us to \textbf{inline} functions in a few more ways, e.g.:
|
\ifger{Haskell erlaubt uns hingegen Funktionen \emph{inline} zu definieren, z.b.:}{Haskell allows us to \textbf{inline} functions in a few more ways, e.g.:}
|
||||||
\begin{itemizep}
|
\begin{itemizep}
|
||||||
\item with \hinline{where}
|
\item \ifger{über}{with} \hinline{where}
|
||||||
\item with \hinline{let...in}
|
\item \ifger{über}{with} \hinline{let...in}
|
||||||
\item anonymously (lambda abstraction)
|
\item \ifger{anonym (lambda Abstraktion}{anonymously (lambda abstraction)}
|
||||||
\end{itemizep}
|
\end{itemizep}
|
||||||
\slidep
|
\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.
|
\ifger{Viele Haskeller mögen es nicht, wenn man nicht-generische Funktionen top-level deklariert. Denn wir können immer noch atomare Funktionsteile haben und diese aber \emph{inline} definieren, sollten sie lediglich einmal benutzte Hilfsfunktionen sein.}{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.}
|
@ -1,13 +1,13 @@
|
|||||||
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?
|
\ifger{Haskell eignet sich besonders gut für Abstraktion, aber wieso eigentlich? Haben wir etwas ähnliches wie java generics oder C++ templates?}{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}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\pause
|
\pause
|
||||||
Even better! Haskell supports polymorphism for both data types and functions.\\
|
\ifger{Noch besser sogar! Haskell erlaubt standardmäßig Polymorphie, ohne komplizierte APIs oder Spracherweiterungen.}{Even better! Haskell supports polymorphism for both data types and functions, out of the box without any language extensions.}\\
|
||||||
Let's start with a polymorphic data type:
|
\ifger{Wir beginnen mit einem polymorphen Datentyp:}{Let's start with a polymorphic data type:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
data List t = Empty | Cons t (List t)
|
data List t = Empty | Cons t (List t)
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
So we just implemented our own singly-linked List. For any type! Let's use it:
|
\ifger{Wir haben soeben unsere eigene singly-linked Liste implementiert. Für jeden Typ! Ein paar Beispiele:}{So we just implemented our own singly-linked List. For any type! Let's use it:}
|
||||||
\pause
|
\pause
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
intList :: List Int
|
intList :: List Int
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
And now we are going to write functions to use it:
|
\ifger{Und jetzt können wir sie nutzen:}{And now we are going to write functions to use it:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
isListEmpty :: List t -> Bool
|
isListEmpty :: List t -> Bool
|
||||||
isListEmpty Emtpy = True
|
isListEmpty Emtpy = True
|
||||||
isListEmpty x = False
|
isListEmpty x = False
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
\pause
|
\pause
|
||||||
We can even have more generic stuff like:
|
\ifger{Wir können sogar Funktionen schreiben wie:}{We can also have:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f :: a -> b
|
f :: a -> b
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
Whatever the function does... it gets 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.
|
\ifger{D.h. was auch immer diese Funktion macht, sie bekommt etwas von einem Typ rein und gibt etwas von einem anderen Typ aus. \hinline{a} und \hinline{b} könnten vom selben Typ sein, müssen aber nicht! D.h. Funktionen dieser Art geben uns häufig mehr Freiheit. Mehr können wir über diese Funktion nicht sagen.}{So, whatever the function does... it gets something of one type and returns something of another type. \hinline{b} \emph{could} be the same type as \hinline{a} here, but it doesn't need to, so functions of this type often give us more freedom! That's all we know about this function.}
|
||||||
\vspace{\baselineskip}
|
\vspace{\baselineskip}
|
||||||
\\
|
\\
|
||||||
\pause
|
\pause
|
||||||
Similarly, remember the function \hinline{head} which gives us the first element of a list? The type signature actually looks like this:
|
\ifger{Erinnern wir uns an die Funktion \hinline{head}. Wir können auf jeder Art von Liste mit ihr operieren. Die Typsignatur:}{Similarly, remember the function \hinline{head} which gives us the first element of a list? The type signature actually looks like this:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
head :: [a] -> a
|
head :: [a] -> a
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
Makes sense?
|
\ifger{Macht Sinn?}{Makes sense?}
|
@ -1,17 +1,17 @@
|
|||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item what is the difference between \hinline{let} and \hinline{where}?
|
\item \ifger{was ist der Unterschied zwischen}{what is the difference between} \hinline{let} \ifger{und}{and} \hinline{where}?
|
||||||
\item what is the difference between \hinline{foldr} and \hinline{foldl}?
|
\item \ifger{was ist der Unterschied zwischen}{what is the difference between} \hinline{foldr} \ifger{und}{and} \hinline{foldl}?
|
||||||
\item what is the difference between explicit and implicit recursion? Give examples
|
\item \ifger{was ist der Unterschied zwischen expliziter und impliziter Rekursion? Beispiele?}{what is the difference between explicit and implicit recursion? Give examples}
|
||||||
\item how many arguments does a haskell function have (strictly speaking)?
|
\item \ifger{wie viele Argumente hat eine Haskell Funktion (streng genommen)?}{how many arguments does a haskell function have (strictly speaking)?}
|
||||||
\item Are these type signatures technically equivalent?
|
\item \ifger{Sind diese Typsignaturen technisch äquivalent?}{Are these type signatures technically equivalent?}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f :: Int -> Int -> Char -> Int -> Int -> Char
|
f :: Int -> Int -> Char -> Int -> Int -> Char
|
||||||
f :: Int -> Int -> (Char -> (Int -> (Int -> Char)))
|
f :: Int -> Int -> (Char -> (Int -> (Int -> Char)))
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
% $
|
% $
|
||||||
\item what do you have to keep in mind in order to make function composition work?
|
\item \ifger{worauf muss man beim verketten von Funktionen (Funktionskomposition) achten?}{what do you have to keep in mind in order to make function composition work?}
|
||||||
\item can you define \hinline{map} and \hinline{filter} in terms of \hinline{foldr}?
|
\item \ifger{können wir}{can you define} \hinline{map} \ifger{und}{and} \hinline{filter} \ifger{mittels}{in terms of} \hinline{foldr}\ifger{ ausdrücken?}{?}
|
||||||
\item simplify (and eta reduce) the following code snippet
|
\item \ifger{vereinfache (und eta reduce) den folgenden Code}{simplify (and eta reduce) the following code snippet}:
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f x y = (\d e -> d * e) x $ y
|
f x y = (\d e -> d * e) x $ y
|
||||||
\end{haskellcode}
|
\end{haskellcode}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
Since we use lists a lot in haskell, we also want some more powerful functions to deal with them. E.g.:
|
\ifger{Da wir in Haskell häufig Listen verwenden, wollen wir auch ein paar mächtige Funktionen kennen lernen, um mit ihnen umzugehen. Z.b.:}{Since we use lists a lot in haskell, we also want some more powerful functions to deal with them. E.g.:}
|
||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item perform an operation on every element on a list
|
\item \ifger{eine Operation auf jedem Element einer Liste ausführen}{perform an operation on every element on a list}
|
||||||
\item keep only some elements in the list, following some criteria
|
\item \ifger{nur einige Elemente in der Liste behalten, nach einem bestimmten Kriterium}{keep only some elements in the list, following some criteria}
|
||||||
\item "summarize" the elements of the list somehow
|
\item \ifger{die Elemente einer Liste irgendwie ''zusammenfassen''}{''summarize'' the elements of the list somehow}
|
||||||
\item ...
|
\item ...
|
||||||
\end{itemize}
|
\end{itemize}
|
||||||
\pause
|
\pause
|
||||||
How do we do that?
|
\ifger{Wie könnte das aussehen?}{How do we do that?}
|
@ -1,6 +1,6 @@
|
|||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item What is haskell? What are the 3 fundamental concepts behind it?
|
\item \ifger{Was ist Haskell? Was sind die 3 fundamentalen Konzepte hinter Haskell?}{What is haskell? What are the 3 fundamental concepts behind it?}
|
||||||
\item How do you do pattern matching?
|
\item \ifger{Wie funktioniert pattern matching?}{How do you do pattern matching?}
|
||||||
\item What is the difference between lists and tuples? How do you construct them?
|
\item \ifger{Was ist der Unterschied zwischen einer Liste und einem Tuple? Wie erzeugt man sie?}{What is the difference between lists and tuples? How do you construct them?}
|
||||||
\item How do you define your own data types?
|
\item \ifger{Wie definieren wir unsere eigenen Datentypen?}{How do you define your own data types?}
|
||||||
\end{itemize}
|
\end{itemize}
|
@ -1,7 +1,7 @@
|
|||||||
\begin{itemize}
|
\begin{itemize}
|
||||||
\item how to write polymorphic data types and functions
|
\item \ifger{wie man polymorphe Funktionen und Datentypen schreibt}{how to write polymorphic data types and functions}
|
||||||
\item how you inline functions
|
\item \ifger{wie man \emph{inline} Funktionen schreibt}{how you inline functions}
|
||||||
\item what currying is and why we need it in haskell
|
\item \ifger{was Currying ist und wieso wir es in Haskell benötigen}{what currying is and why we need it in haskell}
|
||||||
\item how you compose functions
|
\item \ifger{wie man Funktionen verkettet}{how you compose functions}
|
||||||
\item how to abstract out recursion patterns
|
\item \ifger{wie man Rekursionsstrukturen abstrahiert}{how to abstract out recursion patterns}
|
||||||
\end{itemize}
|
\end{itemize}
|
@ -1,4 +1,4 @@
|
|||||||
We use \hinline{where} to define a helper function:
|
\ifger{Wir benutzen}{We use} \hinline{where} \ifger{um eine Hilfsfunktion zu definieren:}{to define a helper function:}
|
||||||
\begin{haskellcode}
|
\begin{haskellcode}
|
||||||
f :: Int -> Int
|
f :: Int -> Int
|
||||||
f x = x + (y 2)
|
f x = x + (y 2)
|
||||||
|
Loading…
Reference in New Issue
Block a user