Tupel
Übersicht: Tupel
Bedeutung und Definition von Tupeln
Durch die Definition von Tupeln kann man Werte miteinander kombinieren, so dass jede Kombination genau einen
Wert des Datentyps bildet, durch den das Tupel definiert wurde. Die Bedeutung der Kombination ist das kartesische
Produkt aus den dem Tupel zugrundeliegenden Typen.
Die häfigste Form eines Tupels ist das Paar. Es wird durch den polymorphen Typ (a,b)
definiert.
Hierbei können die Typen a
und b
beliebig und sogar identisch sein.
Ein Paar lässt sich in Haskell auch auf folgende Art definieren:
01 data Pair a b = MkPair a b
02 MkPair :: a -> b -> Pair a b
|
MkPair
ist eine Funktion mit der angegebenen Typdefinition. Da sie lediglich Elemente
des Datentyps konstruiert wird keine Funktionsweise definiert.
Die Anzahl der Werte in einem allgemeinen Paar (a,b)
ergibt sich aus der Anzahl der
Konstruktoren m für a
und der Anzahl der Konstruktoren n für b
.
Bei beiden Typen muss der undefinierte Wert einbezogen werden und der undefinierte Wert undefined
unterscheidet sich voneinem Paar von undefinierten Werten:
(undefined,undefined) /= undefined
Insgesamt ergeben sich also für ein Paar 1 + (m + 1) * (n + 1) Werte.
Die erstgenannte Syntax kann in Haskell auch verwendet werden und entspricht dem traditionellen Ansatz.
Ein Beispiel für eine Paar in dieser Syntax bestehend aus Integer
und Bool
:
(Integer,Bool)
Mit Hilfe von Haskell kann man viele verschiedene Formen von Tupeln definieren, angefangen mit den aufgezeigten Paaren
über Tripel und Quadrupel bis hin zu n-Tupeln. Bei der Definition ist die Klammersetzung jedoch relevant. So sind
folgende Tupel zu unterscheiden:
01 (a,(b,c))
02 ((a,b),c)
03 (a,b,c)
|
Die erste Zeile beschreibt ein Paar, dass als zweites Element wiederum ein Paar enthält. Im Gegensatz dazu
beschreibt die zweite Zeile ein Paar, dessen erstes Element ein Paar ist. Die dritte Zeile dagegen zeigt ein
Tripel.
Einfache Funktionen für Tupel
Für Paare sind einfache Funktionen vordefiniert, mit denen sich die einzelnen Elemente des Paars wieder
extrahieren lassen.
01 fst :: (a,b) -> a
02 fst (x,y) = x
03 snd :: (a,b) -> b
04 snd (x,y) = y
|
Funktionen mit Paaren von Funktionen als Argument
Die folgenden Definitionen der Funktionen pair
und cross
verwenden die Eigenschaft,
dass auch Paare von Funktionen gebildet werden können. Das Wort cross kommt aus der Kategorientheorie und
wird dort durch die Notation f x g
bezeichnet.
01 pair :: (a -> b,a -> c) -> a -> (b,c)
02 pair (f,g) x = (f x,g x)
03 cross :: (a -> b,c -> d) -> (a,c) -> (b,d)
04 cross (f,g) = pair(f . fst,g . snd)
|
Die Funktionen haben eine Reihe von Eigenschaften die im sogenannten "point-free"-Programmierstil ausgenutzt
werden können. Diese Eigenschaften gelten allerdings nur für binäre Funktionen in der
uncurried Schreibweise.
Die vierte Eigenschaft kann mit Hilfe der anderen Eigenschaften bewiesen
werden. Es wurde an dieser Stelle jedoch darauf verzichtet.
01 fst . pair (f,g) = f
02 snd . pair (f,g) = g
03 pair (f,g) . h = pair (f . h,g . h)
04 cross (f,g) . pair (h,k) = pair(f . h,g . k)
|
Nullary-Typ
Im Rahmen der Tupel existiert ein Nullary-Typ ()
mit den Werten ()
und
undefined
. Dieser Typ kann verwendet werden um Konstanten als Funktionen zu benutzen.
Für die Konstante pi
sieht die Funktionsdefinition beispielsweise folgendermassen aus:
01 pifun :: () -> Float
02 pifun () = 3.14159
|
Konstanten zu Funktionen zu erheben macht vor allem im Kontext der Funktionskomposition Sinn. Hierdurch
lässt sich die Konstante in Form einer Funktion durch eine weitere Funktionskomposition anwenden.
Es kann dadurch die Klammersetzung und die Lesbarkeit der Programme verbessert werden.
Gleichheits- und Ordnungsrelation für Tupel
Für Tupel können leicht Instanzen der Typklassen Eq
und Ord
gebildet
werden. Eine Besonderheit bei der Definition ist hier zu beachten. Die einzelnen Typen, aus denen das Tupel
besteht, müssen ebenfalls Instanzen der jeweiligen Typklasse sein.
Hier die Instanzdeklaration für ein Paar mit lexikografischer Ordnung:
01 instance (Eq a, Eq b) => Eq (a,b) where
02 (x,y) == (u,v) = (x == y) && (y == v)
03
04 instance (Ord a, Ord b) => Ord (a,b) where
05 (x,y) < (u,v) = (x < u) || (x == u && y < v)
|