i

Exkurs - Von der strukturierten zur funktionalen Programmierung

Seiteneffekte

Wenn eine Funktion den Wert einer globalen Variablen verändert, liegt ein Seiteneffekt vor.

Ein Aufruf der folgenden Funktion addiereZaehler führt zu einem Seiteneffekt, da der Wert der globalen Variable zaehler dabei verändert wird.

zaehler = 0

def addiereZaehler(x):
    global zaehler
    zaehler = zaehler + 1
    x = x + zaehler
    return x

# Test
print(zaehler)
print(addiereZaehler(2))
print(zaehler)

Entsprechendes gilt für den Aufruf der Funktion invertiereBild (s.u.), sofern der Parameter L mit einer globalen Variablen aktualisiert wird. Beide Variablen - der Parameter L und die zur Aktualisierung benutzte globale Variablen - verwalten dann dieselbe Liste.

def invertiereBild(L):
    """
    das in L dargestellte Bild wird invertiert
    d.h.: aus 0 wird 1 und aus 1 wird 0
    """
    for i in range(3, len(L)):
        if L[i] == 0:
            L[i] = 1
        else:
            L[i] = 0
    return L

# Test

bild = ['P1', 3, 3, 1, 1, 1, 1, 0, 1, 1, 1, 1]
print(bild)
negativ = invertiereBild(bild)
print(negativ)
print(bild)
negativ = invertiereBild(bild)
print(negativ)
print(bild)

Seiteneffekte führen dazu, dass das Verhalten von Funktionen schwer zu durchschauen ist. Insbesondere bei komplexeren Programmen verliert man leicht den Überblick, welche (beabsichtigten und auch unbeabsichtigten) Nebenwirkungen ein Funktionsaufruf mit Seiteneffekten hat. Man versucht daher, Seiteneffekte möglichst zu vermeiden.

Eine Möglichkeit besteht darin, die Verantwortung für seiteneffektfreie Programme dem Programmentwickler zu überlassen. Dieser muss dann dafür Sorge tragen, dass keine Bausteine mit Seiteneffekten erstellt werden.

Eine andere Möglichkeit besteht darin, die Programmiersprache so zu konzipieren, dass keine Seiteneffekte mehr möglich sind.

Funktionale Programmierung ist (zumindest in der strengen Version) so konzipiert, dass keine Seiteneffekte auftreten können.

Referentielle Transparenz

Seiteneffekte können dazu führen, dass gleiche Ausdrücke unterschiedliche Werte haben. Im folgenden Programm taucht im Ausdruck tausche(getZaehler(), getZaehler()) zweimal im Teilausdruck getZaehler() auf.

from zaehler import *

def tausche(x, y):
    return (y, x)

# Test

print(tausche(2, 3))
print(tausche(1, 1))
print(getZaehler())
print(tausche(getZaehler(), getZaehler()))

Normalerweise würde man erwarten, dass derselbe Teilausdruck getZaehler() auch immer denselben Wert besitzt. Im Programm oben ist das aber nicht der Fall, da es bei der Auswertung der Teilausdrücke zu Seiteneffekten kommt, die den Wert der Teilausdrücke beeinflussen.

Ein solches Verhalten führt leicht zu Fehlern, da man sehr genau auf die Reihenfolge der Auswertung der Teilausdrücke achten muss. Man versucht daher, solche Abhängigkeit zu vermeiden.

Referentielle Transparenz liegt vor, wenn ein Teilausdruck - unabhängig von seiner Position innerhalb eines Ausdrucks und unabhängig vom Zeitpunkt der Auswertung - immer denselben Wert hat.

Funktionale Programmierung ist so konzipiert, dass referentielle Transparenz stets gewährleistet ist.

Ein Dialog über seiteneffektfreie Programmierung

imperativ
Hallo! Ich vertrete hier die imperative Programmierung.

funktional
Hallo, und ich vertrete die funktionale Programmierung.

imperativ
Stimmt es, dass du keine Seiteneffekte erlaubst?

funktional
Ja, so ist es.

imperativ
Und wie machst du das?

funktional
Seiteneffekte entstehen durch Zuweisungen an globale Variablen. Bei mir gibt es gar keine Zuweisungen mehr. Dann kann man auch nicht in die Verlegenheit kommen, einer globalen Variablen etwas zuzuweisen.

imperativ
Klingt einfach. Aber, wie soll man dann einen so einfachen Vorgang wie den folgenden ohne Zuweisungen beschreiben?

ALGORITHMUS Summenberechnung:
{vorher: n ∈ N}
setze s auf 0
setze i auf 0
SOLANGE i <= n:
    erhöhe s um i
    erhöhe i um 1
{nachher: s = 0+1+2+...+n}

funktional
Man muss es halt ganz anders machen.

imperativ
Das kann ich mir nicht so recht vorstellen. Wenn es keine Zuweisungen gibt, dann macht es auch keinen großen Sinn, Variablen einzuführen. Man hat ja keine Möglichkeit, den Wert der Variablen zu verändern. Und wenn man Werte von Variablen nicht verändern kann, dann kann man es durch Anweisungen im Schleifenkörper auch nicht erreichen, dass die Abbruchbedingung einer SOLANGE-Schleife erfüllt wird. Das macht ja alles keinen Sinn mehr.

funktional
Wieso bist du so auf Variablen und Schleifen fixiert?

imperativ
Variablen benötigt man ja wohl zur Datenverwaltung und ohne Schleifen gibt es keine Wiederholungen. Oder sehe ich das ganz falsch?

funktional
Ja, das siehst du etwas zu eng. Wenn du wissen willst, wie mein Berechnungskonzept funktioniert, dann musst du dir den nächsten Abschnitt anschauen.

Suche

v
10.1.1.4
www.inf-schule.de/deklarativ/funktionaleprogrammierung/warumfunktional/exkurs_funktionaleprogrammierung

Rückmeldung geben