i

Zustandsänderungen im funktionalen und imperativen Programmierparadigma

Unveränderlichkeit und Zustandsänderungen

Ein wesentlicher Unterschied zwischen dem imperativen und dem funktionalen Paradigma ist das Fehlen veränderlicher Variablen in der funktionalen Programmierung. In der imperativen Programmierung spielen diese dagegen eine zentrale Rolle. Ein imperatives Programm besitzt einen Programmzustand, der den aktuellen Wert aller verwendeten Variablen darstellt. Der Programmzustand wird somit explizit durch Veränderung von Variablen gesteuert.

Das nachfolgende Python-Programm hat beispielsweise drei Zustände:

  • Zustand 1: Variable x hat den Wert 1
  • Zustand 2: Variable x hat den Wert 3
  • Zustand 3: Variable x hat den Wert 5

#Python
x = 1
x = 3
x = x + 2
Da solche Zustandsänderungen in funktionalen Sprachen nicht möglich sind, nennen wir diese zustandslos.

Aufgabe 1: Zustandsänderungen

Bestehende Datei - funktional_imperativ.rkt
Bestehende Datei - funktional_imperativ.py

(a) Bestimme, wie viele Zustände das untenstehende Python-Programm bei Aufruf der Funktion erhoeheListe annimmt?


#Python
def erhoeheListe(l):
    for i in range(len(l)):
        l[i] = l[i] + 1

testliste = [0, 1, 2, 3]        
erhoeheListe(testliste)        

(b) Erkläre, anhand deines Wissens zur funktionalen Programmierung, warum durch den untenstehenden Aufruf der Funktion erhoehe-liste keine Zustandsänderungen Zustande kommen.


;Racket
(define erhoehe-liste
  (lambda (l)
    (map (lambda (elem) (+ elem 1)) l)))

(define testliste (list 0 1 2 3))
(erhoehe-liste testliste)    

Seiteneffekte

Durch Zustandsänderungen kann es in einem Programm zu Seiteneffekten kommen. Ein Seiteneffekt ist immer dann vorhanden, wenn ein Zustand geändert wird, der außerhalb einer Funktion sichtbar ist. Zum Beispiel durch das Verändern einer globalen Variable, auf die mehrere Funktionen zugreifen können, aber auch beispielsweise durch das Schreiben in externe Dateien.

Seiteneffekte können dazu führen, dass der gleiche Funktionsaufruf unterschiedliche Ergebnisse liefert, je nachdem in welchem Zustand sich das Programm zum Zeitpunkt des Aufrufs befindet.

Aufgabe 2: Seiteneffekte

Bestehende Datei - funktional_imperativ.rkt
Bestehende Datei - funktional_imperativ.py

(a) Analysiere die beiden folgenden Funktionsaufrufe in Racket und Python. Welche Ergebnisse erwartest du? Überprüfe deine Vermutungen anschließend.


;Racket
(anzahl-bestanden notenliste)
(erhoehe-liste notenliste)
(anzahl-bestanden notenliste)

#Python
print(anzahlBestanden(notenliste))
print(erhoeheListe(notenliste))
print(anzahlBestanden(notenliste))     

(b) Erkläre die Ergebnisse der beiden Programmausführungen und beschreibe dabei wo Seiteneffekte auftreten.

Aufgabe 3: Ungewollte Seiteneffekte

Bestehende Datei - funktional_imperativ.py

Seiteneffekte können sowohl gewollt als auch ungewollt auftreten. So könnte beispielsweise die Veränderung der notenliste in Aufgabe 2 in vielen Fällen gewollt sein.

(a) Führe die untenstehende Funktion in Python mit einer beliebigen Liste mehrfach aus und bestimme, wo Seiteneffekte in der Funktion auftreten.


#Python
def getLastElem(l):
    x = l.pop()
    return x

(b) Beurteile, ob es sich für dich hierbei um einen gewollten oder ungewollten Seiteneffekt handelt.

Referenzielle Transparenz

Das funktionale Programmierparadigma erlaubt keine Zustandsänderungen und damit auch keine Seiteneffekte. Hieraus folgt eine wichtige Eigenschaft funktionaler Programme: die referenzielle Transparenz. Referenzielle Transparenz bedeutet, dass ein Ausdruck unabhängig von seiner Position im Programm und unabhängig vom Zeitpunkt der Ausführung immer dasselbe Ergebnis hat.

Verwendung von referenzieller Transparenz

Referenzielle Transparenz ist insbesondere bei der Analyse und Wartung von Programmen nützlich, da nur die tatsächlich relevanten Programmbereiche betrachtet werden können, ohne Seiteneffekte aus anderen Bereichen berücksichtigen zu müssen. Das vereinfacht das Verständnis und die Änderung von Programmcode erheblich. Aus diesem Grund wird funktionale Programmierung häufig in sicherheitskritischen Anwendungen eingesetzt, bei denen Zuverlässigkeit und Vorhersagbarkeit oberste Priorität haben.

Auch in der parallelen Ausführung sind funktionale Programme nützlich. Dort sind Seiteneffekte besonders problematisch, weil sie unerwartetes Verhalten zwischen parallel ausgeführten Programmteilen verursachen können.

Aufgabe 4: Mögliche Seiteneffekte bei parallelen Programmen

Um das Problem mit Zustandsänderungen in parallelen Programmen zu verstehen, stellen wir uns einmal vor, zwei Personen, Liya und Lamar, arbeiten mit zwei Computern gleichzeitig auf denselben für die beiden zugänglichen Variablen.

Zu Beginn sind die Variablen wie folgt definiert:


#Python
x = 3
y = 2

Nun wollen Liya und Lamar die folgenden Änderungen vornehmen:


#Liya
x = x + 1
y = y * 2

#Lamar
y = y + x

(a) Nachdem sowohl Liya als auch Lamar ihre Änderungen durchgeführt haben. Welche Zustände können die Variablen x und y haben?

x == 4 und y == 8

x == 3 und y == 8

x == 4 und y == 12

x == 4 und y == 10

Da Liya und Lamar gleichzeitig Änderungen von zwei Computern aus vornehmen, kann die Reihenfolge, in welcher die Befehle ausgeführt werden, variieren. Sicher ist nur, dass die zwei Befehle von Liya hintereinander ausgeführt werden. Es gibt daher drei mögliche Reihenfolgen, die alle unterschiedliche Werte für y produzieren:


#Möglichkeit 1
x = x + 1 #Liya
y = y * 2 #Liya
y = y + x #Lamar

#Möglichkeit 2
x = x + 1 #Liya
y = y + x #Lamar
y = y * 2 #Liya

#Möglichkeit 3
y = y + x #Lamar
x = x + 1 #Liya
y = y * 2 #Liya

Suche

v
100.137.6.1.1.2 Zustandsänderungen im funktionalen und imperativen Programmierparadigma
Kopieren durch Anklicken

Rückmeldung geben