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 | 11:15 - 11:45 | Thoma | Haskell Class Hierachy
 |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}
 \index{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.
 
 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
 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}
-\subsection{Klammern}
+\subsection{Klammern und Funktionsdeklaration}
 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)$
 definiert:
 
 \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}
 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}
 
 \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}
 \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}
-\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-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{Funktionen höherer Ordnung}
+
 
 \section{Weitere Informationen}
 \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}
                         \end{cases}
                 \end{align*}
+              Erzeugt die Zahlen $0, 1, 1, 2, 3, 5, 8, 13, \dots$
         \item Fakultät:\xindex{Fakultät}
                 \begin{align*}
-                    !: \mdn_0 &\rightarrow \mdn_0\\
+                    !  &: \mdn_0 \rightarrow \mdn_0\\
                     n! &= \begin{cases}
                             1              &\text{falls } n \leq 1\\
                             n\cdot (n-1)!  &\text{sonst}
@@ -28,7 +29,7 @@
                 \end{align*}
         \item \label{bsp:binomialkoeffizient} Binomialkoeffizient:\xindex{Binomialkoeffizient}
                 \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}
                         1                               &\text{falls } k=0 \lor k = n\\
                         \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
 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
     der Funktion höchstens ein rekursiver Aufruf vorkommt.
 \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
     der Rekursive aufruf am Ende des Ausdrucks steht. Der rekursive
     Aufruf darf also insbesondere nicht in einen anderen Ausdruck
     eingebettet sein.
 \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}
+\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 =
     if (k==0) || (k==n)
     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
+
+g :: Floating a => a -> a
 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) 
                then acc 
                else fakAcc (n-1) (n*acc)
+
+fak :: (Eq a, Num a) => a -> a
 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)

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