1. Einführung

1.4 Datentypen

In den seltensten Fällen geht es beim Programmieren nur um Zahlen. Es geht allgemein um Daten, und die kommen in vielen Formaten. Ein Beispiel sind Strings, also Zeichenketten. Auch Strings können Teil von Ausdrücken sein, und Ausdrücke können wiederum Strings ergeben. Wie das genau aussieht, hängt stark von der Programmiersprache ab. Im Moment arbeiten wir aber immer noch sprachunabhängig. Daher schreibe ich einfach mal was:

wort = "Bekanntmachung"                        
lastCharacters(wort, 3)
firstCharacters(wort, 4)
concatenate(wort, "en") // vom Englischen Wort concatenate: aneinanderhängen
length(wort)

Die Funktionen lastCharacters und firstCharacters sollen hier die letzten beziehungsweise ersten \(n\) Zeichen eines Strings ausgeben. Der Ausdruck in Zeile 2 wertet also zu "ung" aus, der in Zeile 3 zu "Beka". Der in Zeile 4 zu "Bekanntmachungen". Der in Zeile 5 zu 14. Können wir mit den Konzepten, die wir bisher gelernt haben, eine Funktion definieren, die die letzten \(k\) Buchstaben abschneidet?

Übungsaufgabe Schreiben Sie eine Funktion removeEnd(wort,k), die die letzten \(k\) Buchstaben abschneidet. Rufen Sie sich in Erinnerung, wie wir Funktionen mit Name, Parametern und Körper geschrieben haben. Sie dürfen davon ausgehen, dass Sie die oben aufgeführten Funktionen lastCharacters, firstCharacters, length, concatenate bereits haben, sowie die üblichen Zahlenoperatoren wie +, - und so weiter haben.
Klicken Sie hier für meine Lösung
removeEnd (wort, k) =        
   firstCharacters(wort, length(wort-4))
Übungsaufgabe Schreiben Sie, im Geiste der vorherigen Übung, eine Funktion, die regelmäßige Verben ins Präteritum setzt. Die Ausdrücke
praeteritum("stellen")
praeteritum("blicken")
praeteritum("kochen")
sollen auswerten zu "stellte", "blickte" und "kochte".
Übungsaufgabe Ihre Lösung der vorherigen Aufgabe scheitert wahrscheinlich an Verben wie schalten, walten, baden, angeln, krabbeln, knabbern, die nicht auf -en enden, aber dennoch als regelmäßig gelten.

Erweitern Sie Ihre Funktion, so dass Sie diese häufigen Sonderfälle abfängt. Denken Sie daran: Sie schreiben hier nicht in einer echten Programmiersprache. Sie können sich also Syntax "ausdenken", wenn Sie sich nicht sicher sind.

Funktionen und Datentypen

Gehen wir nochmal zurück zu der Art und Weise, wie man in der Mathematik eine Funktion definiert: \begin{align} f(x) = x^2 \label{f-naked} \end{align} Wenn man formaler sein will, spezifizieren Mathematiker gerne, welche Eingabewerte \(f\) denn nimmt, und in welcher Menge man landet: \begin{align} f : \mathbb{R} & \rightarrow \mathbb{R} \label{fRR}\\ x & \mapsto x^2 \nonumber \end{align} Und vielleicht will ich \(f\) in einem Kontext verwenden, in dem nur ganze Zahlen vorkommen, und will auch betonen, dass das Ergebnis nie negativ ist. Dann könnte ich beispielsweise schreiben \begin{align} f : \mathbb{Z} & \rightarrow \mathbb{N} \label{fZN} \\ x & \mapsto x^2\nonumber \end{align}

Der "Inhalt" von \(f\) hat sich nicht geändert, nur die "Beschriftung". Was ist nun der Vorteil von (\ref{fRR}) gegenüber (\ref{f-naked})? Der Vorteil ist, dass (\ref{fRR}) eine Art "Bedienungsanleitung" mitliefert. Die Bedienungsanleitung von (\ref{fZN}) ist sogar noch konkreter; auch stellt sie ein Versprechen an den Leser dar: wir werden \(f\) ausschließlich auf ganze Zahlen anwenden.

Um Ihnen zu zeigen, was das nun mit Programmierung zu tun hat, zeige ich Ihnen nun, wie man berechne_kuenftiges_guthaben in verschiedenen Programmiersprachen implementieren würde. Sie erinnern sich:

berechne_kuenftiges_guthaben (startguthaben, zins, jahre) = startguthaben * (1 + zins/100)^jahre 
Beispiel: berechne_kuenftiges_guthaben in verschiedenen Programmiersprachen

Python
def berechne_kuenftiges_guthaben(startguthaben, zins, jahre): 
    return startguthaben * (1 + zins/100.0)**jahre

Javascript
function berechne_kuenftiges_guthaben(startguthaben, zins, jahre) {
    return startguthaben * (1 + zins/100.0)**jahre;
}    

Racket
(define (berechne_kuenftiges_guthaben startguthaben zins jahre)
  (* startguthaben
     (expt (+ 1 (/ zins 100)) jahre)
     )
  )

Java
float berechne_kuenftiges_guthaben(float startguthaben, float zins, float jahre) {
    return startguthaben * Math.exp(1 + zins/100.0, jahre); // in C/C++ schreibt man pow statt Math.exp
}    
Elm
berechne_guthaben : Float -> Float -> Float -> Float
berechne_guthaben startguthaben zins jahre =
    startguthaben * (1.0 + zins / 100.0) ^ jahre

Zwischen diesen Programmiersprachen gibt es irrelevante und relevante Unterschiede. Irrelevant ist beispielsweise, dass Python und Javascript ** für die Exponentiation verwenden, Java Math.exp, Racket expt Elm ^. Dass man in Racket die seltsam anmutende Präfixschreibweise

(* startguthaben (expt (+ 1 (/ zins 100)) jahre)
anstatt einem deutlich vertrauterem
startguthaben * (expt (1 + (zins / 100), jahre)
verwendet, macht das Programmieren in Racket anfangs anstrengend, ist aber letztendlich auch nur ein oberflächlicher Unterschied.

Übungsaufgabe Finden Sie einen fundamentalen Unterschied zwischen Python, Javascript und Racket auf der einen und Java und Elm auf der anderen Seite.

Weitere Datentypen

Typischerweise haben Sie mindestens zwei Datentypen für Zahlen: ganze Zahlen, auf Englisch Integer, und Gleitkommazahlen, auf Englisch Floating Point Numbers oder kurz Float, mit denen man Zahlen mit Nachkommastellen darstellen kann. Strings haben Sie ja oben auch schon kennengelernt.

Beim Programmieren werden Sie weitere Datentypen kennenlernen (z.B. Booelan für Wahrheitswerte wie true und false) und auch selbst neue Datentypen definieren. Wollen Sie zum Beispiel in einem Zeichenprogramm das geometrische Objekt Kreis repräsentieren, so benötigen Sie

  • zwei Zahlen (wahrscheinlich Float) für den Mittelpunkt,
  • eine Zahl für den Radius
  • eine Farbe für den Rand
  • eine Farbe für das Innere
  • eine Zahl für die Randstärke.
Die Farben wiederum müssen auch als Datentyp dargestellt werden. Dann haben Sie wahrscheinlich eine ganze Sammlung geometrischer Objekte, die Sie in einer Liste von solchen Objekten speichern wollen. Sie brauchen also einen Datentyp, der eine ganze Liste repräsentieren kann.

Beim Programmieren, insbesondere beim Programmieren mit Elm, besteht ein großer Teil der Arbeit darin, sich zu überlegen, welche Datentypen man braucht, und diese dann zu definieren.

Nun setzen Sie sich an einen Rechner und legen los.