Haskell
Dieser Artikel wurde für die folgenden Ubuntu-Versionen getestet:
Ubuntu 24.04 Noble Numbat
Du möchtest den Artikel für eine weitere Ubuntu-Version testen? Mitarbeit im Wiki ist immer willkommen! Dazu sind die Hinweise zum Testen von Artikeln zu beachten.
Zum Verständnis dieses Artikels sind folgende Seiten hilfreich:
Haskell 🇬🇧 ist eine polymorphe, statisch typisierte und rein funktionale Programmiersprache. Ausdrücke werden nur bei Bedarf ausgewertet ("lazy evaluation"). Der Name kommt vom Logiker Haskell Curry. Haskell baut auf dem Lambda-Kalkül, einer formalen Sprache zur Untersuchung von Funktionen, auf. Daher kommt auch das Logo in Form eines Lambdas.
Installation¶
GHC¶
Der Haskell-Compiler GHC (The Glorious Glasgow Haskell Compilation system) kann direkt aus den Quellen installiert werden[1]:
ghc (universe)
Befehl zum Installieren der Pakete:
sudo apt-get install ghc
weitere Haskell Module¶
In den Paketquellen gibt es eine Reihe von Haskell Modulen für spezieller Aufgabe. Diese erkannt man daran, dass der Paketname mit haskell- beginnt.
Bedienung¶
Haskell-Programme können sowohl über den Interpreter geschrieben werden, als auch direkt ausgeführt werden. Ein Kompilieren zu Bytecode ist ebenfalls möglich.
Interpreter¶
Der interaktive Interpreter kann mit dem Aufruf von
ghci
im Terminal[2] gestartet werden. Der Interpreter erfasst die Befehle erst mal nur zeilenweise. Mehrzeilige Anweisungen müssen in einem speziellen Block :{
:}
geschrieben werden.
Hinweis:
Im interaktiven Modus müssen alle Zuweisungen (auch die von Funktionen) mit let
erfolgen.
Beispiel 1¶
Die Fakultät von einer natürlichen Zahl kann z.B. mit der product-Funktion aus der Standardbibliothek (Prelude) errechnet werden:
1 | let factorial n = product [1..n] |
Die Funktion kann jetzt für die Zahl 5 aufgerufen werden.
1 | factorial 5 |
Als Ergebnis erhält man als Ausgabe dann 120
.
Beispiel 2¶
Ohne die Standardbibliothek zu nutzen, kann folgende rekursive Funktion das Problem lösen:
1 2 3 4 5 6 | :{ let { factorial 0 = 1; factorial n = n * factorial (n - 1); } :} |
Der Aufruf erfolgt wie bei Beispiel 1. Da der Code zwischen den Blockmarkern in eine einzige Zeile eingelesen wird, müssen die Befehle durch einen Semikolon ;
getrennt werden. Eine Einrückung ist im normalen Code zwingend, entfällt aber dadurch, dass alles letztendlich in einer Zeile steht.
Beispiel 3¶
Da Haskell nur bei Bedarf die Ausdrücke auflöst ("lazy evaluation"), kann auf einfache Weise mit unendlich großen Mengen gearbeitet werden. Hier werden die ersten zehn geraden Zahlen aus einer unendlichen Liste (null bis unendlich) ausgegeben:
1 | take 10 [x | x <- [0..], x `mod` 2 == 0] |
Die Befehlssequenz wird direkt ausgeführt, weswegen hier auch das let
nicht notwendig. Also Ausgabe dieser Befehlssequenz erhält man als Ausgabe
[0,2,4,6,8,10,12,14,16,18]
Quelldatei¶
Wie bei anderen Skriptsprachen, kann auch Haskellcode direkt in eine Datei geschrieben und ausgeführt werden. Die Datei mit dem Quellcode muss dabei die Dateiendung .hs haben, sonst erhält man beim Kompilieren des Codes eine Fehlermeldung. Die Datei wird dann mit dem Interpreter direkt ausgeführt[2]:
ghc HASKELLDATEI.hs
Wenn man den Befehl ausführt findet man im Verzeichnis jetzt drei neue Dateien:
HASKELLDATEI.hi: Dies ist eine Interface-Datei, in der Haskell Informationen speichert, die benötigt werden, wenn weitere Module kopiert werden, die HASKELLDATEI.hs benötigen.
HASKELLDATEI.o: Dies ist die Object-Datei, welche den kompilierten Haskell-Code enthält.
HASKELLDATEI: Dies ist die ausführbare Datei, welche aus dem Haskell-Quellcode generiert wurde.
Die Interface-Datei und die Objekt-Datei können anschließend gelöscht werden.
Beispiel 1¶
Ein einfaches Hello-World-Programm:
1 2 3 | -- Einfaches Hello-World Beispiel. main :: IO () main = putStrLn "Hello, World!" |
Es gehört zum guten Stil, zu allen Funktionen entsprechende Typdeklarationen zu schreiben (entsprechend die erste Zeile main :: IO ()
).
Beispiel 2¶
Die Fakultät wird hier je nach Benutzereingabe berechnet:
1 2 3 4 5 6 7 8 9 10 | factorial :: Int -> Int factorial n -- anstatt "Pattern matching" werden | n == 0 = 1 -- hier "Guards" (mit '|') verwendet | otherwise = n * factorial (n - 1) main :: IO () main = do putStrLn "Welche Fakultät soll berechnet werden?" n <- getLine putStrLn . show $ factorial $ read n |
Beispiel 3¶
Hier wird ebenfalls die Fakultät berechnet, das vorherige Beispiel allerdings noch gegen fehlerhafte Benutzereingaben abgesichert.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import Data.Maybe factorial :: Integer -> Integer -- Integer hat keine Größenbeschränkung factorial 0 = 1 -- im Gegensatz zu Int factorial n = n * factorial (n - 1) maybeRead :: Read a => String -> Maybe a maybeRead s = case reads s of [(x, "")] -> Just x _ -> Nothing getIntfromString :: String -> Maybe Integer getIntfromString str = maybeRead str main :: IO () main = do putStrLn "Welche Fakultät soll berechnet werden?" input <- getLine let maybeInt = getIntfromString input in case maybeInt of Just n -> if (n >= 0) then putStrLn $ "Das Ergebnis von " ++ show n ++ "! ist: " ++ show (factorial n) else error "Keine positive Zahl übergeben!" Nothing -> error "Keine Ganze Zahl übergeben!" |
Ab GHC 7.6 existiert die Funktion maybeRead
bereits im Modul Text.Read 🇬🇧.
Weitere / alternative Compiler¶
Weitere Compiler sind auf Wikipedia zusammengefasst: Haskell - Implementations - Die meisten davon sind nicht in den Standardquellen verfügbar.
Links¶
Haskell 🇬🇧 Homepage
Haskell Hierarchical Libraries 🇬🇧 - Bibliotheksindex
Sammlung von Links 🇬🇧 zu verschiedenen Dokumentationen und Kursen für Haskell
Learn You a Haskell for Great Good! 🇬🇧 - Kurzweiliges Einsteigertutorial