2014-03-01 20:04:19 +01:00
|
|
|
%!TEX root = Programmierparadigmen.tex
|
2014-02-01 13:46:33 +01:00
|
|
|
\chapter{Haskell}
|
|
|
|
\index{Haskell|(}
|
2014-03-24 18:48:38 +01:00
|
|
|
Haskell ist eine funktionale Programmiersprache, die 1990 in Version~1.0 veröffentlicht
|
|
|
|
wurde. Namensgeber ist Haskell Brooks Curry, der die mathematischen Grundlagen der funktionalen Programmierung entwickelte.
|
2014-02-01 15:32:13 +01:00
|
|
|
|
|
|
|
Wichtige Konzepte sind:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item Funktionen höherer Ordnung
|
|
|
|
\item anonyme Funktionen (sog. Lambda-Funktionen)
|
|
|
|
\item Pattern Matching
|
|
|
|
\item Unterversorgung
|
|
|
|
\item Typinferenz
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
Haskell kann mit \enquote{Glasgow Haskell Compiler} mittels
|
|
|
|
\texttt{ghci} interpretiert und mittels
|
|
|
|
|
|
|
|
\section{Erste Schritte}
|
|
|
|
Haskell kann unter \href{http://www.haskell.org/platform/}{\path{www.haskell.org/platform/}}
|
|
|
|
für alle Plattformen heruntergeladen werden. Unter Debian-Systemen
|
|
|
|
ist das Paket \texttt{ghc} bzw. \texttt{haskell-platform} relevant.
|
2014-02-01 14:39:16 +01:00
|
|
|
|
2014-02-04 14:07:24 +01:00
|
|
|
\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}
|
2014-02-02 11:59:07 +01:00
|
|
|
|
2014-02-04 14:07:24 +01:00
|
|
|
Kompiliere ihn mit \texttt{ghc -o hello hello-world.hs}. Es wird eine
|
|
|
|
ausführbare Datei erzeugt.
|
2014-02-02 11:59:07 +01:00
|
|
|
|
2014-02-24 11:44:57 +01:00
|
|
|
Alternativ kann es direkt mit \texttt{runghc hello-world.hs} ausgeführt werden.
|
|
|
|
|
2014-02-01 13:46:33 +01:00
|
|
|
\section{Syntax}
|
2014-02-04 14:07:24 +01:00
|
|
|
\subsection{Klammern und Funktionsdeklaration}
|
2014-02-01 15:32:13 +01:00
|
|
|
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}
|
|
|
|
|
2014-02-04 14:07:24 +01:00
|
|
|
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}
|
|
|
|
|
2014-02-24 11:44:57 +01:00
|
|
|
\todo[inline]{Gibt es Funktionsdeklarationen, die bis auf Wechsel des Namens und der Reihenfolge äquivalent sind?}
|
2014-02-04 14:07:24 +01:00
|
|
|
|
2014-02-01 15:32:13 +01:00
|
|
|
\subsection{if / else}
|
2014-03-30 13:59:51 +02:00
|
|
|
Das folgende Beispiel definiert den Binomialkoeffizienten (vgl. \cref{bsp:binomialkoeffizient}):
|
2014-02-01 15:32:13 +01:00
|
|
|
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/binomialkoeffizient.hs}
|
|
|
|
|
2014-02-24 11:44:57 +01:00
|
|
|
Das könnte man auch mit sog. Guards machen:\xindex{Guard}
|
|
|
|
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/binomialkoeffizient-guard.hs}
|
2014-02-01 15:32:13 +01:00
|
|
|
|
|
|
|
\subsection{Rekursion}
|
|
|
|
Die Fakultätsfunktion wurde wie folgt implementiert:
|
|
|
|
\[fak(n) := \begin{cases}
|
|
|
|
1 &\text{falls } n=0\\
|
|
|
|
n \cdot fak(n) &\text{sonst}
|
|
|
|
\end{cases}\]
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/fakultaet.hs}
|
|
|
|
|
|
|
|
Diese Implementierung benötigt $\mathcal{O}(n)$ rekursive Aufrufe und
|
|
|
|
hat einen Speicherverbrauch von $\mathcal{O}(n)$. Durch einen
|
|
|
|
\textbf{Akkumulator}\xindex{Akkumulator} kann dies verhindert werden:
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/fakultaet-akkumulator.hs}
|
|
|
|
|
2014-02-02 17:48:55 +01:00
|
|
|
\subsection{Listen}
|
2014-02-04 14:07:24 +01:00
|
|
|
\begin{itemize}
|
|
|
|
\item \texttt{[]} erzeugt die leere Liste,
|
|
|
|
\item \texttt{[1,2,3]} erzeugt eine Liste mit den Elementen $1, 2, 3$
|
2014-03-30 13:59:51 +02:00
|
|
|
\item \texttt{:}\xindex{: (Haskell)} wird \textbf{cons}\xindex{cons} genannt und ist
|
2014-02-04 14:07:24 +01:00
|
|
|
der Listenkonstruktor.
|
2014-03-30 13:59:51 +02:00
|
|
|
\item \texttt{list !! i}\xindex{"!"! (Haskell)} gibt das $i$-te Element von \texttt{list} zurück.
|
2014-02-04 14:07:24 +01:00
|
|
|
\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}
|
2014-03-23 19:28:44 +01:00
|
|
|
\item \texttt{last [1,9,1,3]} gibt 3 zurück.
|
2014-02-04 14:07:24 +01:00
|
|
|
\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}).
|
2014-03-23 19:28:44 +01:00
|
|
|
\item \texttt{null list} prüft, ob \texttt{list} leer ist.
|
|
|
|
\item \texttt{take 3 [1,2,3,4,5]} gibt \texttt{[1,2,3]} zurück.
|
|
|
|
\item \texttt{drop 3 [1,2,3,4,5]} gibt \texttt{[4,5]} zurück.
|
2014-02-04 14:07:24 +01:00
|
|
|
\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}
|
2014-02-02 17:48:55 +01:00
|
|
|
|
2014-02-02 18:01:02 +01:00
|
|
|
\subsubsection{Beispiel in der interaktiven Konsole}
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/listenoperationen.sh}
|
|
|
|
|
2014-03-23 19:28:44 +01:00
|
|
|
\subsubsection{List-Comprehensions}\xindex{List-Comprehension}%
|
2014-02-04 14:07:24 +01:00
|
|
|
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}
|
|
|
|
|
2014-03-23 19:28:44 +01:00
|
|
|
\begin{beispiel}[List-Comprehension]
|
|
|
|
Das folgende Beispiel zeigt, wie man mit List-Comprehensions die unendliche
|
|
|
|
Liste aller pythagoreischen Tripels erstellen kann:
|
|
|
|
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/pythagorean-triples.hs}
|
|
|
|
\end{beispiel}
|
|
|
|
|
2014-02-04 14:07:24 +01:00
|
|
|
\subsection{Strings}
|
|
|
|
\begin{itemize}
|
|
|
|
\item Strings sind Listen von Zeichen:\\
|
|
|
|
\texttt{tail "ABCDEF"} gibt \texttt{"BCDEF"} zurück.
|
|
|
|
\end{itemize}
|
|
|
|
|
2014-03-18 19:31:04 +01:00
|
|
|
\subsection{Let und where}\xindex{let}\xindex{where}%
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/let-where-bindung.hs}
|
|
|
|
|
2014-03-30 13:59:51 +02:00
|
|
|
\subsection{Funktionskomposition}\xindex{. (Haskell)}\xindex{Funktionskomposition}%
|
2014-03-25 19:48:20 +01:00
|
|
|
In Haskell funktioniert Funktionskomposition mit einem Punkt:
|
|
|
|
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/function-composition.hs}
|
|
|
|
|
|
|
|
Dabei ergibt \texttt{h (-3)} in der mathematischen Notation
|
|
|
|
\[(g \circ f) (-3) = f(g(-3)) = f(-4) = 16\]
|
|
|
|
und \texttt{i (-3)} ergibt
|
|
|
|
\[(f \circ g) (-3) = g(f(-3)) = g(9) = 8\]
|
|
|
|
Es ist also anzumerken, dass die Reihenfolge \underline{nicht} der mathematischen
|
|
|
|
konvention entspricht.
|
|
|
|
|
2014-03-30 13:59:51 +02:00
|
|
|
\subsection{\$ (Dollar-Zeichen)}\xindex{\$ (Haskell)}
|
|
|
|
Das Dollar-Zeichen \$ dient in Haskell dazu Klammern zu vermeiden. So sind die
|
|
|
|
folgenden Zeilen äquivalent:
|
|
|
|
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/dollar-example.hs}
|
|
|
|
|
2014-02-04 14:07:24 +01:00
|
|
|
\section{Typen}
|
2014-03-01 20:04:19 +01:00
|
|
|
\subsection{Standard-Typen}
|
|
|
|
Haskell kennt einige Basis-Typen:
|
|
|
|
\begin{itemize}
|
|
|
|
\item \textbf{Int}: Ganze Zahlen. Der Zahlenbereich kann je nach Implementierung variieren,
|
|
|
|
aber der Haskell-Standart garantiert, dass das Intervall
|
|
|
|
$[-2^{29}, 2^{29}-1]$ abgedeckt wird.
|
|
|
|
\item \textbf{Integer}: beliebig große ganze Zahlen
|
|
|
|
\item \textbf{Float}: Fließkommazahlen
|
|
|
|
\item \textbf{Double}: Fließkommazahlen mit doppelter Präzision
|
|
|
|
\item \textbf{Bool}: Wahrheitswerte
|
|
|
|
\item \textbf{Char}: Unicode-Zeichen
|
|
|
|
\end{itemize}
|
|
|
|
|
|
|
|
Des weiteren gibt es einige strukturierte Typen:
|
|
|
|
\begin{itemize}
|
2014-03-30 13:59:51 +02:00
|
|
|
\item Listen: z.~B. \texttt{[1,2,3]}
|
|
|
|
\item Tupel: z.~B. \texttt{(1,'a',2)}
|
2014-03-01 20:04:19 +01:00
|
|
|
\item Brüche (Fractional, RealFrac)
|
|
|
|
\item Summen-Typen: Typen mit mehreren möglichen Repräsentationen
|
|
|
|
\end{itemize}
|
|
|
|
|
|
|
|
\subsection{Typinferenz}
|
2014-02-04 14:07:24 +01:00
|
|
|
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}
|
|
|
|
|
2014-03-10 15:39:59 +01:00
|
|
|
\subsection{type}\xindex{type}%
|
2014-03-02 18:02:13 +01:00
|
|
|
Mit \texttt{type} können Typsynonyme erstellt werden:
|
|
|
|
|
2014-03-10 15:39:59 +01:00
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/alt-types.hs}
|
2014-03-02 18:02:13 +01:00
|
|
|
|
2014-03-10 15:39:59 +01:00
|
|
|
\subsection{data}\xindex{data}%
|
2014-03-02 18:02:13 +01:00
|
|
|
Mit dem Schlüsselwort \texttt{data} können algebraische Datentypen\xindex{Datentyp!algebraischer}
|
|
|
|
erzeugt werden:
|
|
|
|
|
2014-03-10 15:39:59 +01:00
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/data-example.hs}
|
2014-03-02 18:02:13 +01:00
|
|
|
|
2014-03-18 15:45:40 +01:00
|
|
|
\section{Lazy Evaluation}\xindex{Lazy Evaluation}%
|
2014-03-01 20:04:19 +01:00
|
|
|
Haskell wertet Ausdrücke nur aus, wenn es nötig ist.
|
|
|
|
|
|
|
|
\begin{beispiel}[Lazy Evaluation]
|
|
|
|
Obwohl der folgende Ausdruck einen Teilausdruck hat, der einen Fehler zurückgeben
|
|
|
|
würde, kann er aufgrund der Lazy Evaluation zu 2 evaluiert werden:
|
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=lazy-evaluation.hs]{haskell}{scripts/haskell/lazy-evaluation.hs}
|
|
|
|
\end{beispiel}
|
|
|
|
|
2014-02-01 13:46:33 +01:00
|
|
|
\section{Beispiele}
|
2014-02-04 14:07:24 +01:00
|
|
|
\subsection{Quicksort}
|
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=qsort.hs]{haskell}{scripts/haskell/qsort.hs}
|
2014-02-01 15:32:13 +01:00
|
|
|
|
2014-02-04 14:07:24 +01:00
|
|
|
\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:
|
2014-02-01 15:32:13 +01:00
|
|
|
|
2014-02-04 14:07:24 +01:00
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=qsort.hs]{haskell}{scripts/haskell/qsort-unterversorg.hs}
|
|
|
|
|
|
|
|
\subsection{Fibonacci}\xindex{Fibonacci}
|
2014-02-01 13:46:33 +01:00
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=fibonacci.hs]{haskell}{scripts/haskell/fibonacci.hs}
|
2014-02-04 14:07:24 +01:00
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=fibonacci-akk.hs]{haskell}{scripts/haskell/fibonacci-akk.hs}
|
2014-03-18 15:45:40 +01:00
|
|
|
\xindex{zipWith}
|
2014-02-04 14:07:24 +01:00
|
|
|
\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}
|
2014-02-01 13:46:33 +01:00
|
|
|
|
2014-03-20 13:42:52 +01:00
|
|
|
Die unendliche Liste alle Fibonacci-Zahlen, also der Fibonacci-\textit{Stream}\xindex{Stream}
|
|
|
|
wird wie folgt erzeugt:
|
|
|
|
|
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=fibonacci-stream.hs]{haskell}{scripts/haskell/fibonacci-stream.hs}
|
|
|
|
|
2014-03-18 19:31:04 +01:00
|
|
|
\subsection{Polynome}\xindex{Polynome}\xindex{zipWith}\xindex{foldr}\xindex{tail}%
|
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=polynome.hs]{haskell}{scripts/haskell/polynome.hs}
|
|
|
|
|
|
|
|
\subsection{Hirsch-Index}\xindex{Hirsch-Index}\xindex{Ord}\xindex{Num}%
|
|
|
|
\textbf{Parameter}: Eine Liste $L$ von Zahlen aus $\mdn$\\
|
|
|
|
\textbf{Rückgabe}: $\max \Set{n \in \mdn | n \leq \|\Set{i \in L | i \geq n}\|}$
|
|
|
|
|
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=hirsch-index.hs]{haskell}{scripts/haskell/hirsch-index.hs}
|
|
|
|
|
|
|
|
\subsection{Lauflängencodierung}\xindex{Lauflängencodierung}\xindex{splitWhen}\xindex{group}\xindex{concat}%
|
|
|
|
|
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=lauflaengencodierung.hs]{haskell}{scripts/haskell/lauflaengencodierung.hs}
|
2014-03-12 21:07:00 +01:00
|
|
|
|
2014-03-23 19:28:44 +01:00
|
|
|
\subsection{Intersections}\xindex{Intersections}\xindex{List-Comprehension}%
|
2014-03-20 13:42:52 +01:00
|
|
|
|
2014-03-23 19:28:44 +01:00
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=intersect.hs]{haskell}{scripts/haskell/intersect.hs}
|
2014-03-20 13:42:52 +01:00
|
|
|
|
2014-03-01 20:04:19 +01:00
|
|
|
\subsection{Funktionen höherer Ordnung}\xindex{Folds}\xindex{foldl}\xindex{foldr}\label{bsp:foldl-und-foldr}
|
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=folds.hs]{haskell}{scripts/haskell/folds.hs}
|
2014-02-04 14:07:24 +01:00
|
|
|
|
2014-03-12 21:07:00 +01:00
|
|
|
\subsection{Chruch-Zahlen}
|
|
|
|
\inputminted[linenos, numbersep=5pt, tabsize=4, frame=lines, label=church.hs]{haskell}{scripts/haskell/church.hs}
|
2014-02-01 15:32:13 +01:00
|
|
|
|
2014-03-25 19:48:20 +01:00
|
|
|
\subsection{Trees}\xindex{tree}\xindex{map!tree}%
|
|
|
|
Einen Binärbaum kann man in Haskell so definieren:
|
|
|
|
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/binary-tree.hs}
|
|
|
|
|
|
|
|
Einen allgemeinen Baum so:
|
|
|
|
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/general-tree.hs}
|
|
|
|
|
|
|
|
Hier ist \texttt{t} der polymorphe Typ des Baumes. \texttt{t} gibt also an welche
|
|
|
|
Elemente der Baum enthält.
|
|
|
|
|
|
|
|
Man kann auf einem solchen Baum auch eine Variante von \texttt{map} und
|
|
|
|
\texttt{reduce} definieren,
|
|
|
|
also eine Funktion \texttt{mapT}, die eine weitere Funktion \texttt{f} auf jeden
|
|
|
|
Knoten anwendet:
|
|
|
|
|
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/mapt.hs}
|
|
|
|
|
2014-03-08 13:16:08 +01:00
|
|
|
\subsection{Standard Prelude}
|
|
|
|
Hier sind die Definitionen eininger wichtiger Funktionen:
|
2014-03-18 15:45:40 +01:00
|
|
|
\xindex{zipWith}\xindex{zip}
|
2014-03-08 13:16:08 +01:00
|
|
|
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/standard-definitions.hs}
|
|
|
|
|
2014-02-01 15:32:13 +01:00
|
|
|
\section{Weitere Informationen}
|
|
|
|
\begin{itemize}
|
2014-02-04 15:05:14 +01:00
|
|
|
\item \href{http://hackage.haskell.org/package/base-4.6.0.1}{\path{hackage.haskell.org/package/base-4.6.0.1}}: Referenz
|
2014-02-01 15:32:13 +01:00
|
|
|
\item \href{http://www.haskell.org/hoogle/}{\path{haskell.org/hoogle}}: Suchmaschine für das Haskell-Manual
|
|
|
|
\item \href{http://wiki.ubuntuusers.de/Haskell}{\path{wiki.ubuntuusers.de/Haskell}}: Hinweise zur Installation von Haskell unter Ubuntu
|
|
|
|
\end{itemize}
|
|
|
|
|
2014-02-01 13:46:33 +01:00
|
|
|
\index{Haskell|)}
|
|
|
|
|