Strukturierung: Definitionen
Definitionen in Racket
Wenn wir Programmierelemente (z.B. Daten, Ausdrücke oder Funktionen) in einem Programm häufig verwenden wollen, kann es Sinn machen, diesen einen Namen zuzuordnen, um sie nicht bei jeder Nutzung neu erzeugen zu müssen. Dies ist mittels einer Definition möglich.
define
gesetzt:
;Definitionen von Daten
(define e 2.71828)
(define willkommenText "Hallo und herzlich willkommen in der funktionalen Programmierung")
;Definitionen von Ausdrücken
(define pi-quadrat (* 3.14159 3.14159))
(define startMessage (string-append "Hallo" "Welt!"))
;Definitionen von bestehenden Funktionen
(define addition +)
(define anzahlZeichen string-length)
;Definition einer neuen Funktion
(define minus-eins
(lambda (x)
(- x 1)))
Aufgabe 1: Rechnen mit Definitionen
(a) Definiere $\pi$ auf fünf Nachkommastellen genau.
(b) Berechne das Volumen eines Zylinders mit dem Radius 10 cm und der Höhe 20 cm.
$V = r^2 \cdot \pi \cdot h$
(c) Berechne das Volumen einer Kugel mit dem Radius 10 cm.
$V = \frac{4}{3} \cdot \pi \cdot r^3$
Aufgabe 2: Neubennenung von Funktionen durch Definitionen
Neben den Bezeichnungen First-Element und Rest sind auch die Bezeichnungen Head und Tail geläufig. Daher wollen wir in Racket die Möglichkeit schaffen, auch diese Bezeichnungen zu nutzen.
(a) Definiere head
und tail
und überprüfe deine Definitionen mit folgenden Ausdrücken:
;Erwartete Rückgabe: 10
> (head (list 10 11 12))
;Erwartete Rückgabe: #<list 11 12>
> (tail (list 10 11 12))
Eindeutigkeit von Definitionen
Wir haben bereits gelernt, dass Definitionen nicht veränderlich sind. Tatsächlich gilt dies in funktionalen Programmiersprachen für alle Daten. Die Unveränderlichkeit (engl. Immutability) stellt somit ein zentrales Konzept in der funktionalen Programmierung dar. Wenn wir Änderungen an Daten vornehmen (zum Beispiel beim Hinzufügen eines Elements an eine Liste), werden neue Daten erzeugt; die alten Daten bleiben unverändert.
Unveränderlichkeit bedeutet, dass bestehende Daten nicht verändert werden können, sondern bei Änderungen neue Daten erzeugt werden.
Entsprechend müsste man davon ausgehen, dass auch der Name einer Definition immer eindeutig ist und kein zweites Mal im Programmcode als Definition vorkommen kann. Dies trifft jedoch nicht zu ...
Aufgabe 3: Gleicher Name für verschiedene Definitionen
(a) Übertrage die Definition durchmesser
in deine Datei. Definiere anschließend
radius
mithilfe eines Ausdrucks, der durchmesser
verarbeitet.
(define durchmesser 20)
(b) Übertrage die Funktion volumen-zylinder
in deine Datei.
Wo findest du hier überall Definitionen?
;Berechnet das Volumen eins Zylinders
(: volumen-zylinder (real -> real))
(check-expect (volumen-zylinder radius 20) 6283.18)
(check-expect (volumen-zylinder 6 12) 1357.16688)
(define volumen-zylinder
(lambda (r h)
(define rquad (* r r))
(* rquad (* pi h))
) )
(c) Versuche, die Definition rquad
außerhalb der Funktion volumen-zylinder
zu nutzen.
(d) Versuche, die Definition rquad
außerhalb der Funktion neu zu definieren. Überprüfe anschließend
die Korrektheit der Funktion volumen-zylinder
mittels der Tests.
(e) Überlege zusammen mit deinem Partner, warum es möglich ist, dass in unserem Code zwei verschiedene Definitionen von
rquad
existieren.
Globale und lokale Definition
Der gleiche Name kann unter bestimmten Bedingungen in einem Programm tatsächlich für mehrere Definitionen genutzt werden. Es bleibt jedoch immer eindeutig, welche der verschiedenen Definitionen vom Programm zu nutzen ist.
Aufgabe 4: Nutzung lokaler Definitionen
(a) Erstelle analog zu Aufgabe 3 (b) eine Funktion volumen-kugel
. Verwende im Funktionskörper mindestens
eine lokale Definition.