2
0
Fork 0
mirror of https://github.com/MartinThoma/LaTeX-examples.git synced 2025-04-26 06:48:04 +02:00

Viel zu Haskell ergänzt; Funktionen höherer Ordnung beschrieben

This commit is contained in:
Martin Thoma 2014-02-04 14:07:24 +01:00
parent aa2454bb30
commit 78368fa6e9
17 changed files with 220 additions and 24 deletions

View file

@ -8,3 +8,4 @@ in dem Erstellen dieses Skripts steckt:
|01.02.2014 | 14:45 - 15:30 | Thoma | Haskell angefangen |01.02.2014 | 14:45 - 15:30 | Thoma | Haskell angefangen
|01.02.2014 | 11:15 - 11:45 | Thoma | Haskell Class Hierachy |01.02.2014 | 11:15 - 11:45 | Thoma | Haskell Class Hierachy
|01.02.2014 | 16:00 - 17:00 | Thoma | Abschnitt über Rekursion hinzugefügt |01.02.2014 | 16:00 - 17:00 | Thoma | Abschnitt über Rekursion hinzugefügt
|04.02.2014 | 13:00 - 14:00 | Thoma | Viel zu Haskell ergänzt; Funktionen höherer Ordnung beschrieben

View file

@ -1,7 +1,7 @@
\chapter{Haskell} \chapter{Haskell}
\index{Haskell|(} \index{Haskell|(}
Haskell ist eine funktionale Programmiersprache, die von Haskell Haskell ist eine funktionale Programmiersprache, die von Haskell
Brooks Curry entwickelt wurde und 1990 in Version~1.0 veröffentlicht Brooks Curry entwickelt und 1990 in Version~1.0 veröffentlicht
wurde. wurde.
Wichtige Konzepte sind: Wichtige Konzepte sind:
@ -21,24 +21,44 @@ Haskell kann unter \href{http://www.haskell.org/platform/}{\path{www.haskell.org
für alle Plattformen heruntergeladen werden. Unter Debian-Systemen für alle Plattformen heruntergeladen werden. Unter Debian-Systemen
ist das Paket \texttt{ghc} bzw. \texttt{haskell-platform} relevant. ist das Paket \texttt{ghc} bzw. \texttt{haskell-platform} relevant.
\section{Typen} \subsection{Hello World}
Siehe \cref{fig:haskell-type-hierarchy}: Speichere folgenden Quelltext als \texttt{hello-world.hs}:
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=hello-world.hs]{haskell}{scripts/haskell/hello-world.hs}
\begin{figure}[htp] Kompiliere ihn mit \texttt{ghc -o hello hello-world.hs}. Es wird eine
\centering ausführbare Datei erzeugt.
\resizebox{0.9\linewidth}{!}{\input{figures/haskell-type-classes.tex}}
\caption{Hierarchie der Haskell Standardklassen}
\label{fig:haskell-type-hierarchy}
\end{figure}
\section{Syntax} \section{Syntax}
\subsection{Klammern} \subsection{Klammern und Funktionsdeklaration}
Haskell verzichtet an vielen Stellen auf Klammern. So werden im Haskell verzichtet an vielen Stellen auf Klammern. So werden im
Folgenden die Funktionen $f(x) := \frac{\sin x}{x}$ und $g(x) := x \cdot f(x^2)$ Folgenden die Funktionen $f(x) := \frac{\sin x}{x}$ und $g(x) := x \cdot f(x^2)$
definiert: definiert:
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/einfaches-beispiel-klammern.hs} \inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/einfaches-beispiel-klammern.hs}
Die Funktionsdeklarationen mit den Typen sind nicht notwendig, da
die Typen aus den benutzten Funktionen abgeleitet werden.
Zu lesen ist die Deklaration wie folgt:
\begin{center}
\texttt{[Funktionsname] :: \texttt{[Typendefinitionen]} => \texttt{Signatur}}
\end{center}
\begin{itemize}
\item[T. Def.] Die Funktion \texttt{f} benutzt als Parameter bzw. Rückgabewert
einen Typen. Diesen Typen nennen wir \texttt{a} und er ist
vom Typ \texttt{Floating}. Auch \texttt{b}, \texttt{wasweisich}
oder etwas ähnliches wäre ok.
\item[Signatur] Die Signatur liest man am einfachsten von hinten:
\begin{itemize}
\item \texttt{f} bildet auf einen Wert vom Typ \texttt{a} ab und
\item \texttt{f} hat genau einen Parameter \texttt{a}
\end{itemize}
\end{itemize}
\todo[inline]{Gibt es Funktionsdeklarationen, die äquivalent? (bis auf wechsel des namens und der Reihenfolge)}
\subsection{if / else} \subsection{if / else}
Das folgende Beispiel definiert den Binomialkoeffizienten (vgl. \cref{bsp:binomialkoeffizient}) Das folgende Beispiel definiert den Binomialkoeffizienten (vgl. \cref{bsp:binomialkoeffizient})
@ -61,23 +81,86 @@ hat einen Speicherverbrauch von $\mathcal{O}(n)$. Durch einen
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/fakultaet-akkumulator.hs} \inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/fakultaet-akkumulator.hs}
\subsection{Listen} \subsection{Listen}
\todo[inline]{Cons-Operator, Unendliche Listen} \begin{itemize}
\item \texttt{[]} erzeugt die leere Liste,
\item \texttt{[1,2,3]} erzeugt eine Liste mit den Elementen $1, 2, 3$
\item \texttt{:} wird \textbf{cons}\xindex{cons} genannt und ist
der Listenkonstruktor.
\item \texttt{head list} gibt den Kopf von \texttt{list} zurück,
\texttt{tail list} den Rest:
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/list-basic.sh}
\item \texttt{null list} prüft, ob \texttt{list} leer ist.
\item \texttt{length list} gibt die Anzahl der Elemente in \texttt{list} zurück.
\item \texttt{maximum [1,9,1,3]} gibt 9 zurück (analog: \texttt{minimum}).
\item \texttt{last [1,9,1,3]} gibt 3 zurück.
\item \texttt{reverse [1,9,1,3]} gibt \texttt{[3,1,9,1]} zurück.
\item \texttt{elem item list} gibt zurück, ob sich \texttt{item} in \texttt{list} befindet.
\end{itemize}
\subsubsection{Beispiel in der interaktiven Konsole} \subsubsection{Beispiel in der interaktiven Konsole}
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/listenoperationen.sh} \inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/listenoperationen.sh}
\subsubsection{List-Comprehensions}\xindex{List-Comprehension}
List-Comprehensions sind kurzschreibweisen für Listen, die sich an
der Mengenschreibweise in der Mathematik orientieren. So entspricht
die Menge
\begin{align*}
myList &= \Set{1,2,3,4,5,6}\\
test &= \Set{x \in myList | x > 2}
\end{align*}
in etwa folgendem Haskell-Code:
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/list-comprehensions.sh}
\subsection{Strings}
\begin{itemize}
\item Strings sind Listen von Zeichen:\\
\texttt{tail "ABCDEF"} gibt \texttt{"BCDEF"} zurück.
\end{itemize}
\section{Typen}
In Haskell werden Typen aus den Operationen geschlossfolgert. Dieses
Schlussfolgern der Typen, die nicht explizit angegeben werden müssen,
nennt man \textbf{Typinferent}\xindex{Typinferenz}.
Haskell kennt die Typen aus \cref{fig:haskell-type-hierarchy}.
Ein paar Beispiele zur Typinferenz:
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/typinferenz.sh}
\begin{figure}[htp]
\centering
\resizebox{0.9\linewidth}{!}{\input{figures/haskell-type-classes.tex}}
\caption{Hierarchie der Haskell Standardklassen}
\label{fig:haskell-type-hierarchy}
\end{figure}
\section{Beispiele} \section{Beispiele}
\subsection{Hello World} \subsection{Quicksort}
Speichere folgenden Quelltext als \texttt{hello-world.hs}: \inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=qsort.hs]{haskell}{scripts/haskell/qsort.hs}
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=hello-world.hs]{haskell}{scripts/haskell/hello-world.hs}
Kompiliere ihn mit \texttt{ghc -o hello hello-world.hs}. Es wird eine \begin{itemize}
ausführbare Datei erzeugt. \item Die leere Liste ergibt sortiert die leere Liste.
\item Wähle das erste Element \texttt{p} als Pivotelement und
teile die restliche Liste \texttt{ps} in kleinere und
gleiche sowie in größere Elemente mit \texttt{filter} auf.
Konkateniere diese beiden Listen mit \texttt{++}.
\end{itemize}
\subsection{Fibonacci} Durch das Ausnutzen von Unterversorgung\xindex{Unterversorgung} lässt
sich das ganze sogar noch kürzer schreiben:
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=qsort.hs]{haskell}{scripts/haskell/qsort-unterversorg.hs}
\subsection{Fibonacci}\xindex{Fibonacci}
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=fibonacci.hs]{haskell}{scripts/haskell/fibonacci.hs} \inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=fibonacci.hs]{haskell}{scripts/haskell/fibonacci.hs}
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=fibonacci-akk.hs]{haskell}{scripts/haskell/fibonacci-akk.hs}
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=fibonacci-zip.hs]{haskell}{scripts/haskell/fibonacci-zip.hs}
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=fibonacci-pattern-matching.hs]{haskell}{scripts/haskell/fibonacci-pattern-matching.hs}
\subsection{Quicksort} \subsection{Quicksort}
\subsection{Funktionen höherer Ordnung}
\section{Weitere Informationen} \section{Weitere Informationen}
\begin{itemize} \begin{itemize}

View file

@ -18,9 +18,10 @@
fib(n-1) + fib(n-2) &\text{sonst} fib(n-1) + fib(n-2) &\text{sonst}
\end{cases} \end{cases}
\end{align*} \end{align*}
Erzeugt die Zahlen $0, 1, 1, 2, 3, 5, 8, 13, \dots$
\item Fakultät:\xindex{Fakultät} \item Fakultät:\xindex{Fakultät}
\begin{align*} \begin{align*}
!: \mdn_0 &\rightarrow \mdn_0\\ ! &: \mdn_0 \rightarrow \mdn_0\\
n! &= \begin{cases} n! &= \begin{cases}
1 &\text{falls } n \leq 1\\ 1 &\text{falls } n \leq 1\\
n\cdot (n-1)! &\text{sonst} n\cdot (n-1)! &\text{sonst}
@ -28,7 +29,7 @@
\end{align*} \end{align*}
\item \label{bsp:binomialkoeffizient} Binomialkoeffizient:\xindex{Binomialkoeffizient} \item \label{bsp:binomialkoeffizient} Binomialkoeffizient:\xindex{Binomialkoeffizient}
\begin{align*} \begin{align*}
\binom{\cdot}{\cdot}: \mdn_0 \times \mdn_0 &\rightarrow \mdn_0\\ \binom{\cdot}{\cdot} &: \mdn_0 \times \mdn_0 \rightarrow \mdn_0\\
\binom{n}{k} &= \begin{cases} \binom{n}{k} &= \begin{cases}
1 &\text{falls } k=0 \lor k = n\\ 1 &\text{falls } k=0 \lor k = n\\
\binom{n-1}{k-1}+\binom{n-1}{k} &\text{sonst} \binom{n-1}{k-1}+\binom{n-1}{k} &\text{sonst}
@ -79,20 +80,54 @@ Mit Hilfe der Formel von Moivre-Binet folgt:
Dabei ist der Speicherbedarf $\mathcal{O}(n)$. Dieser kann durch Dabei ist der Speicherbedarf $\mathcal{O}(n)$. Dieser kann durch
das Benutzen eines Akkumulators signifikant reduziert werden.\todo{TODO} das Benutzen eines Akkumulators signifikant reduziert werden.\todo{TODO}
\begin{definition}[linear rekursive Funktion]\xindex{Funktion!linear rekursive} \begin{definition}[linear rekursive Funktion]\xindex{Funktion!linear rekursive}%
Eine Funktion heißt linear rekursiv, wenn in jedem Definitionszweig Eine Funktion heißt linear rekursiv, wenn in jedem Definitionszweig
der Funktion höchstens ein rekursiver Aufruf vorkommt. der Funktion höchstens ein rekursiver Aufruf vorkommt.
\end{definition} \end{definition}
\begin{definition}[endrekursive Funktion]\xindex{Funktion!endrekursive}\xindex{tail recursive} \begin{definition}[endrekursive Funktion]\xindex{Funktion!endrekursive}\xindex{tail recursive}%
Eine Funktion heißt endrekursiv, wenn in jedem Definitionszweig Eine Funktion heißt endrekursiv, wenn in jedem Definitionszweig
der Rekursive aufruf am Ende des Ausdrucks steht. Der rekursive der Rekursive aufruf am Ende des Ausdrucks steht. Der rekursive
Aufruf darf also insbesondere nicht in einen anderen Ausdruck Aufruf darf also insbesondere nicht in einen anderen Ausdruck
eingebettet sein. eingebettet sein.
\end{definition} \end{definition}
\todo[inline]{Beispiele für linear rekusrive, endrekursive Funktionen (alle Kombinationen+gegenbeispiele} Auf Englisch heißen endrekursive Funktionen \textit{tail recursive}.
\index{Rekursion|(} \begin{beispiel}[Linear- und endrekursive Funktionen]
\begin{bspenum}
\item \texttt{fak n = if (n==0) then 1 else (n * fak (n-1))}\\
ist eine linear rekursive Funkion, aber nicht endrekursiv,
da nach der Rückgabe von \texttt{fak (n-1)} noch die Multiplikation
ausgewertet werden muss.
\item \texttt{fakAcc n acc = if (n==0) then acc else fakAcc (n-1) (n*acc)}\\
ist eine endrekursive Funktion.
\item \texttt{fib n = n <= 1 ? n : fib(n-1) + fib (n-2)}\\
ist weder linear- noch endrekursiv.
\end{bspenum}
\end{beispiel}
\index{Rekursion|)}
\section{Backtracking} \section{Backtracking}
\index{Backtracking|(}
\index{Backtracking|)}
\section{Funktionen höherer Ordnung}
Funktionen höherer Ordnung sind Funktionen, die auf Funktionen arbeiten.
Bekannte Beispiele sind:
\begin{itemize}
\item \texttt{map(function, list)}\xindex{map}\\
\texttt{map} wendet \texttt{function} auf jedes einzelne
Element aus \texttt{list} an.
\item \texttt{filter(function, list)}\xindex{filter}\\
\texttt{filter} gibt eine Liste aus Elementen zurück, für
die \texttt{function} mit \texttt{true} evaluiert.
\item \texttt{reduce(function, list)}\xindex{reduce}\\
\texttt{function} ist für zwei Elemente aus \texttt{list}
definiert und gibt ein Element des gleichen Typs zurück.
Nun steckt \texttt{reduce} zuerst zwei Elemente aus \texttt{list}
in \texttt{function}, merkt sich dann das Ergebnis und nimmt
so lange weitere Elemente aus \texttt{list}, bis jedes
Element genommen wurde.
\end{itemize}

View file

@ -1,3 +1,4 @@
binom :: (Eq a, Num a, Num a1) => a -> a -> a1
binom n k = binom n k =
if (k==0) || (k==n) if (k==0) || (k==n)
then 1 then 1

View file

@ -1,2 +1,5 @@
f :: Floating a => a -> a
f x = sin x / x f x = sin x / x
g :: Floating a => a -> a
g x = x * (f (x*x)) g x = x * (f (x*x))

View file

@ -1,4 +1,7 @@
fakAcc :: (Eq a, Num a) => a -> a -> a
fakAcc n acc = if (n==0) fakAcc n acc = if (n==0)
then acc then acc
else fakAcc (n-1) (n*acc) else fakAcc (n-1) (n*acc)
fak :: (Eq a, Num a) => a -> a
fak n = fakAcc n 1 fak n = fakAcc n 1

View file

@ -1 +1,2 @@
fak :: (Eq a, Num a) => a -> a
fak n = if (n==0) then 1 else n * fak (n-1) fak n = if (n==0) then 1 else n * fak (n-1)

View file

@ -0,0 +1,5 @@
fibAkk n n1 n2
| (n == 0) = n1
| (n == 1) = n2
| otherwise = fibAkk (n - 1) n2 (n1 + n2)
fib n = fibAkk n 0 1

View file

@ -0,0 +1,3 @@
fib 0 = 0
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)

View file

@ -0,0 +1 @@
fib = 0 : 1 : zipWith (+) fibs (tail fibs)

View file

@ -1 +1,4 @@
fibs = 0 : 1 : zipWith (+) fibs (tail fibs) fib n
| (n == 0) = 0
| (n == 1) = 1
| otherwise = fib (n - 1) + fib (n - 2)

View file

@ -0,0 +1,12 @@
Prelude> head []
*** Exception: Prelude.head: empty list
Prelude> tail []
*** Exception: Prelude.tail: empty list
Prelude> tail [1]
[]
Prelude> head [1]
1
Prelude> null []
True
Prelude> null [[]]
False

View file

@ -0,0 +1,4 @@
Prelude> let mylist = [1,2,3,4,5,6]
Prelude> let test = [x | x <- mylist, x>2]
Prelude> test
[3,4,5,6]

View file

@ -0,0 +1,3 @@
qsort [] = []
qsort (p:ps) = (qsort (filter (<=p) ps))
++ p:(qsort (filter (> p) ps))

View file

@ -0,0 +1,3 @@
qsort [] = []
qsort (p:ps) = (qsort (filter (\x -> x<=p) ps))
++ p:(qsort (filter (\x -> x> p) ps))

View file

@ -0,0 +1,35 @@
Prelude> let x = \x -> x*x
Prelude> :t x
x :: Integer -> Integer
Prelude> x(2)
4
Prelude> x(2.2)
<interactive>:6:3:
No instance for (Fractional Integer)
arising from the literal `2.2'
Possible fix: add an instance declaration for
(Fractional Integer)
In the first argument of `x', namely `(2.2)'
In the expression: x (2.2)
In an equation for `it': it = x (2.2)
Prelude> let mult = \x y->x*y
Prelude> mult(2,5)
<interactive>:9:5:
Couldn't match expected type `Integer' with
actual type `(t0, t1)'
In the first argument of `mult', namely `(2, 5)'
In the expression: mult (2, 5)
In an equation for `it': it = mult (2, 5)
Prelude> mult 2 5
10
Prelude> :t mult
mult :: Integer -> Integer -> Integer
Prelude> let concat = \x y -> x ++ y
Prelude> concat [1,2,3] [3,2,1]
[1,2,3,3,2,1]
Prelude> :t concat
concat :: [a] -> [a] -> [a]