IHaskell Folge 10: Einleitung In Funktionen
iHaskell Folge 10: Einleitung in Funktionen
Hey Leute! Willkommen zurück zu einer weiteren spannenden Folge von iHaskell. Heute tauchen wir tief in ein super wichtiges Thema ein: Funktionen . Wenn ihr bisher gedacht habt, Programmieren wäre nur eine Aneinanderreihung von Befehlen, dann macht euch jetzt bereit, denn Funktionen sind quasi die Bausteine, die eure Programme erst richtig leistungsfähig und übersichtlich machen. Stellt euch Funktionen wie kleine, spezialisierte Roboter vor, die eine bestimmte Aufgabe erledigen. Ihr gebt ihnen vielleicht ein paar Zutaten (das sind die Argumente), und sie liefern euch ein fertiges Gericht (das Ergebnis) zurück. Oder sie führen einfach nur eine Aktion aus, wie das Einschalten einer Lampe. In Haskell sind Funktionen nicht nur Werkzeuge, sondern sie sind zentral . Sie sind die erste Bürger der Sprache, was bedeutet, dass wir sie genauso behandeln können wie Zahlen oder Text. Wir können sie an andere Funktionen übergeben, sie in Listen packen oder sie von anderen Funktionen zurückgeben lassen. Das klingt vielleicht erstmal etwas abstrakt, aber glaubt mir, das eröffnet unglaubliche Möglichkeiten für eleganten und effizienten Code . In dieser Folge werden wir uns anschauen, wie wir Funktionen definieren, wie wir sie mit Argumenten füttern und wie wir die Ergebnisse nutzen. Wir werden auch die Magie der Typsignaturen kennenlernen, die uns helfen, den Überblick zu behalten und Fehler zu vermeiden. Also schnallt euch an, denn wir starten unsere Reise in die wunderbare Welt der Haskell-Funktionen!
Table of Contents
Was genau sind Funktionen in Haskell?
Also, was sind diese
Funktionen
in Haskell eigentlich im Kern? Stellt euch eine Funktion wie eine
mathematische Formel
vor, die ihr kennt. Zum Beispiel
f(x) = x + 2
. Ihr gebt eine Zahl für
x
ein, und die Funktion gibt euch eine neue Zahl zurück, die um 2 größer ist. In Haskell ist das ganz ähnlich, aber wir haben ein paar coole Erweiterungen. Eine Funktion in Haskell ist im Grunde eine
Abbildung von einer Eingabe zu einer Ausgabe
. Wir definieren, was eine Funktion tun soll, und dann können wir sie mit verschiedenen Eingaben aufrufen, um unterschiedliche Ausgaben zu erhalten. Das Coole an Haskell ist, dass Funktionen
rein
sind. Das bedeutet, eine Funktion gibt für dieselbe Eingabe immer dieselbe Ausgabe zurück und sie hat keine
Nebenwirkungen
. Sie verändert nichts außerhalb von sich selbst. Das ist ein riesiger Unterschied zu vielen anderen Programmiersprachen, wo Funktionen oft Dinge im Hintergrund tun, die man nicht direkt sieht. Diese Reinheit macht Haskell-Code
leichter zu verstehen, zu testen und zu parallelisieren
. Wenn ihr eine reine Funktion habt, könnt ihr euch darauf verlassen, dass sie sich immer gleich verhält, egal wo oder wann ihr sie aufruft. Das ist wie ein zuverlässiger Mechanismus. Wir können Funktionen auch miteinander
kombinieren
, um komplexere Funktionalitäten zu erstellen. Stellt euch vor, ihr habt eine Funktion, die eine Zahl verdoppelt, und eine andere, die 3 addiert. Ihr könnt diese beiden Funktionen so zusammenfügen, dass ihr zuerst die Zahl verdoppelt und dann 3 addiert. Das nennt man
Funktionskomposition
, und es ist ein mächtiges Konzept, das wir uns später noch genauer anschauen werden. Aber für den Anfang ist es wichtig zu verstehen, dass Funktionen in Haskell nicht nur Code-Blöcke sind, sondern sie sind
echte Werte
, mit denen wir arbeiten können. Das ist einer der Gründe, warum Haskell so flexibel und ausdrucksstark ist. Wir können damit
abstrakte Konzepte
auf eine sehr natürliche Weise modellieren, was bei der Entwicklung komplexer Software Gold wert ist.
Deine erste Haskell-Funktion definieren
Lasst uns das Ganze jetzt mal
praktisch
machen, Leute! Wie schreiben wir eigentlich unsere eigene Funktion in Haskell? Es ist einfacher, als ihr vielleicht denkt. Wir brauchen zwei Dinge:
einen Namen für unsere Funktion
und
eine Definition, was sie tun soll
. Nehmen wir mal wieder das Beispiel von
f(x) = x + 2
. In Haskell würden wir das so schreiben:
addTwo x = x + 2
Hier ist
addTwo
der Name unserer Funktion. Das
x
davor ist das
Argument
, also die Eingabe, die unsere Funktion erwartet. Und
x + 2
ist der
Körper
der Funktion, also die Berechnung, die durchgeführt wird. Wenn wir diese Funktion aufrufen wollen, schreiben wir einfach ihren Namen gefolgt von dem Wert, den wir übergeben wollen. Zum Beispiel:
addTwo 5
Das Ergebnis wäre
7
. Ziemlich straightforward, oder? Aber jetzt kommt der Clou, der Haskell so besonders macht:
Typsignaturen
. Bevor wir die Funktion definieren, ist es eine gute Praxis, ihr einen Typ zu geben. Das sagt dem Compiler (und uns selbst!), welche Art von Daten die Funktion erwartet und zurückgibt. Für
addTwo
würde das so aussehen:
addTwo :: Int -> Int
addTwo x = x + 2
Die Zeile
addTwo :: Int -> Int
ist die Typsignatur. Sie sagt: ‘Die Funktion
addTwo
nimmt einen
Integer
(eine ganze Zahl,
Int
) als Eingabe und gibt einen
Integer
(
Int
) als Ausgabe zurück.’ Der Pfeil
->
steht für ‘funktioniert auf’ oder ‘ergibt’. Warum ist das wichtig? Erstens hilft es uns,
Fehler zu vermeiden
. Wenn wir versuchen würden,
addTwo
mit einem Text zu verwenden, würde der Compiler sofort meckern, weil der Typ nicht passt. Zweitens macht es unseren Code
verständlicher
. Wenn wir später eine Funktion sehen, wissen wir sofort, was sie erwartet und was sie zurückgibt. Wir können auch Funktionen erstellen, die
mehrere Argumente
nehmen. Zum Beispiel eine Funktion, die zwei Zahlen addiert:
addNumbers :: Int -> Int -> Int
addNumbers x y = x + y
Hier nimmt
addNumbers
zwei
Int
s entgegen und gibt einen
Int
zurück. Wenn wir sie aufrufen, geben wir die Argumente hintereinander an:
addNumbers 3 5
ergibt
8
. Das ist das Fundament, auf dem wir aufbauen werden. Fangt an, mit einfachen Funktionen zu experimentieren, und ihr werdet sehen, wie mächtig dieses Konzept ist!
Argumente und Rückgabewerte: Das Herzstück jeder Funktion
Okay, Leute, lasst uns mal tiefer in die
Argumente
und
Rückgabewerte
eintauchen, denn das ist wirklich das Herzstück jeder Funktion, egal in welcher Sprache. In Haskell sind wir da ein bisschen anders unterwegs, und das ist eine gute Sache! Wenn wir eine Funktion definieren, legen wir fest, welche Informationen sie benötigt, um ihre Arbeit zu erledigen. Diese Informationen nennen wir
Argumente
oder manchmal auch
Parameter
. Denkt daran, wie eine Kaffeemaschine ein Argument braucht: Kaffeepulver. Ohne das Pulver kann sie keinen Kaffee machen. Genauso braucht eine Funktion ihre Argumente, um ein Ergebnis zu produzieren. Bei der Funktion
addTwo x = x + 2
war
x
unser Argument. Wir haben ihr eine Zahl gegeben, und sie hat damit gearbeitet. Was passiert, wenn eine Funktion
mehrere
Argumente braucht? Wie bei
addNumbers x y = x + y
, wo wir
x
und
y
brauchen, um die Summe zu berechnen. In Haskell ist das tatsächlich so, als ob die Funktion nur
ein
Argument nimmt, das Ergebnis davon aber eine
neue Funktion
ist, die das nächste Argument erwartet. Klingt komisch? Nennen wir das
Currying
. Wenn wir
addNumbers
aufrufen, mit
addNumbers 3
, dann ist das Ergebnis nicht
8
, sondern eine neue Funktion, die darauf wartet, das zweite Argument zu erhalten. Erst wenn wir dann
(addNumbers 3) 5
(oder einfach
addNumbers 3 5
) aufrufen, bekommen wir das endgültige Ergebnis
8
. Das ist ein super mächtiges Konzept, das uns erlaubt, Funktionen flexibel zu gestalten. Wir können zum Beispiel eine Funktion schreiben, die eine andere Funktion nimmt und sie mit einem festen Argument