Funktionale Programmierung mit Haskell/ Funktionen auf Tupel

Aus Wikibooks

Funktionen auf Tupel[Bearbeiten]

Tupel sind eine andere Form der Datenspeicherung. Sie unterscheiden sich in mehreren Punkten von Listen:

  • Tupel werden mit runden Klammern dargestellt, etwa (3,4)
  • Tupel besitzen eine feste Zahl von Elementen, d.h. man kann einen Tupel nicht von (3,4) auf (3,4,5) erweitern. Tupel mit einem einzigen Element sind nicht erlaubt, ein 1-Tupel könnte man mit einem Ausdruck verwechseln. Leere Tupel sind erlaubt.
  • Elemente eines Tupels sind immer vom selben Typ, d.h. ein Tupel ("September", 1) kann nicht auf (9,1) geändert werden.

Mit diesen Eigenschaften haben Tupel völlig andere Einsatzgebiete als Listen. Sie werden z.B. gerne als Key/Value-Paare verwendet, wenn (wie im unten stehenden Beispiel) zu jedem Land genau eine Vorwahl hinterlegt werden soll.
Mathematische Hintergründe zum Tupel werden auch in der Wikipedia erklärt.

Hier ein paar Anwendungsbeispiele:

Dialog in ghci
Prelude> let ff = (8,9) -- Zuweisung eines Tupels
Prelude> ff -- kann man sich so anzeigen lassen
(8,9)

Prelude> fst ff  -- Erstes Element des Tupels (geht nur für 2-Tupel)
8

Prelude> snd ff  -- Zweites Element des Tupels (geht nur für 2-Tupel)
9

Prelude> let n = () -- das leere Tupel
Prelude> n
()

Prelude> map fst [(1, 2), (3, 4), (5, 6)] -- Eine Liste von 2-Tupeln, aus der wir die ersten Elemente herausholen
[1,3,5]

Prelude> let x = [(1, 2), (3, 4, 5), (6, 7)] -- Liefert einen Fehler, denn ein 2-Tupel ist kein 3-Tupel
Prelude>

Ein Beispielprogramm mit Key-Value-Tupeln[Bearbeiten]

Da sich Tupel gut für Key-Value-Datenspeicherung eignen, wird diese Technik im folgenden Programm näher erläutert. Dabei werden Zugriffe auf eine Ländervorwahl-Liste dargestellt. Der Key ist dabei das Land, der Value ist die Vorwahl. In dem Beispiel findet der Zugriff auf die Tupel mittels der lookup-Funktion statt, außerdem wird auch das Haskell-spezifische Maybe-Konstrukt verwendet.

Ein Beispielprogramm mit Key-Value-Tupeln
module KeyValue
where

import Data.Maybe (fromJust, isNothing)

type Land    = String
type Vorwahl = Integer
type VorwahlListe = [(Land, Vorwahl)]
laenderListe :: VorwahlListe
laenderListe =  [("Afghanistan", 93), 
                 ("Ägypten",20), 
                 ("Albanien", 355),
                 ("Algerien", 213)] -- usw... 

main = do
       putStrLn "Bitte ein Land eingeben"
       datString <- getLine
       let land = datString
       let vorw = lookup land laenderListe
       if isNothing vorw
           then putStrLn ("Das Land "++land++" ist nicht hinterlegt")
           else putStrLn ("die Vorwahl von "++land++" ist +"++ show (fromJust vorw))

Erläuterung:
Mit Land, Vorwahl und VorwahlListe werden drei benutzerdefinierte Typen angelegt. Die Funktion lookup holt mit dem Land-Schlüssel die Vorwahl aus der laenderListe. lookup liefert einen Maybe-Typ zurück, das bedeutet: Falls ein Wert zurückgeliefert wird, wird ihm ein Just vorangestellt. Es muss mit fromJust oder durch Pattern-Matching vom eigentlichen Rückgabewert extrahiert werden. Wenn kein Wert zurückgeliefert wird (z.B. bei einer unsinnigen Abfrage wie "Egypten") muss dieser Fall speziell abgefangen werden. Dies geschieht in der if-Anweisung.

Zur Laufzeit sieht das so aus:

Dialog in ghci
$> ghci KeyValue.hs
...
Ok, modules loaded: KeyValue.
*KeyValue> main
Bitte ein Land eingeben
Ägypten
die Vorwahl von Ägypten ist +20
*KeyValue> main
Bitte ein Land eingeben
Egypten
Das Land Egypten ist nicht hinterlegt
*KeyValue>

Benutzerdefinierte Typen mit Tupeln[Bearbeiten]

Tupel eignen sich auch dazu, Benutzerdefinierte Typen anzulegen. Beispielsweise kann man ein Datum mit Jahr, Monat und Tag definieren:

Dialog in ghci
Prelude> type Day = (Integer, Int, Int) -- Definition eines Tags als Jahr, Monat und Tag
Prelude> let datum = (2014,12,3) :: Day -- Zuweisung eines Datums
Prelude> datum -- lassen wir es uns anzeigen
(2014,12,3)
Prelude>