Browse Source

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

Martin Thoma 11 years ago
parent
commit
78368fa6e9

+ 1 - 0
documents/Programmierparadigmen/Arbeitszeit.md

@@ -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

+ 100 - 17
documents/Programmierparadigmen/Haskell.tex

@@ -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}
-Siehe \cref{fig:haskell-type-hierarchy}:
+\subsection{Hello World}
+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]
-    \centering
-    \resizebox{0.9\linewidth}{!}{\input{figures/haskell-type-classes.tex}}
-    \caption{Hierarchie der Haskell Standardklassen}
-    \label{fig:haskell-type-hierarchy}
-\end{figure}
+Kompiliere ihn mit \texttt{ghc -o hello hello-world.hs}. Es wird eine
+ausführbare Datei erzeugt.
 
 
 \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}
-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}
+\subsection{Quicksort}
+\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=qsort.hs]{haskell}{scripts/haskell/qsort.hs}
 
 
-Kompiliere ihn mit \texttt{ghc -o hello hello-world.hs}. Es wird eine
-ausführbare Datei erzeugt.
+\begin{itemize}
+    \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}
+
+Durch das Ausnutzen von Unterversorgung\xindex{Unterversorgung} lässt
+sich das ganze sogar noch kürzer schreiben:
 
 
-\subsection{Fibonacci}
+\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}

BIN
documents/Programmierparadigmen/Programmierparadigmen.pdf


+ 41 - 6
documents/Programmierparadigmen/Programmiertechniken.tex

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

+ 1 - 0
documents/Programmierparadigmen/scripts/haskell/binomialkoeffizient.hs

@@ -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

+ 3 - 0
documents/Programmierparadigmen/scripts/haskell/einfaches-beispiel-klammern.hs

@@ -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))

+ 3 - 0
documents/Programmierparadigmen/scripts/haskell/fakultaet-akkumulator.hs

@@ -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

+ 1 - 0
documents/Programmierparadigmen/scripts/haskell/fakultaet.hs

@@ -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)

+ 5 - 0
documents/Programmierparadigmen/scripts/haskell/fibonacci-akk.hs

@@ -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

+ 3 - 0
documents/Programmierparadigmen/scripts/haskell/fibonacci-pattern-matching.hs

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

+ 1 - 0
documents/Programmierparadigmen/scripts/haskell/fibonacci-zip.hs

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

+ 4 - 1
documents/Programmierparadigmen/scripts/haskell/fibonacci.hs

@@ -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)

+ 12 - 0
documents/Programmierparadigmen/scripts/haskell/list-basic.sh

@@ -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

+ 4 - 0
documents/Programmierparadigmen/scripts/haskell/list-comprehensions.sh

@@ -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]

+ 3 - 0
documents/Programmierparadigmen/scripts/haskell/qsort-unterversorg.hs

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

+ 3 - 0
documents/Programmierparadigmen/scripts/haskell/qsort.hs

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

+ 35 - 0
documents/Programmierparadigmen/scripts/haskell/typinferenz.sh

@@ -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]
+