Funktionsprogrammierung für Loop-Nebeneffekt


8

Ich versuche herauszufinden, warum eine lokale Variable oder eine for-Schleife in einer Funktion nicht als reine funktionale Programmierung angesehen wird.

Angesichts dieser Funktion:

int as_int(char *str)
{
    int acc; /* accumulate the partial result */

    for (acc = 0; isdigit(*str); str++) {
        acc = acc * 10 + (*str - '0');
    }

    return acc;
}

Unter welchen Umständen wäre die Variable acc ein Nebeneffekt? Selbst in einer gleichzeitigen Umgebung hätte jeder Aufruf der Funktion eine eigene Kopie von acc. Ich verstehe also nicht ganz, warum es in der funktionalen Programmierung nicht erlaubt ist.


3
Es gibt keine Nebenwirkungen. Siehe: programmers.stackexchange.com/questions/196112/…
Ben Aaronson

5
as_intist eine reine Funktion, aber der Code darin ist nicht rein.
Doval

1
Reiner Code ist normalerweise unveränderlichen Variablen zugeordnet. accist veränderlich.
Florian Margaine

Antworten:


11

Looping in der funktionalen Programmierung ist nicht mit Steueranweisungen getan wie forund while, es gemacht mit expliziten Aufrufen von Funktionen wie map, foldoder Rekursion - all das beinhaltet den innere Schleife Anruf in einer anderen Funktion . Wenn der Schleifencode Variablen außerhalb der Schleife mutiert, manipuliert diese innere Schleifenfunktion Variablen außerhalb ihres Gültigkeitsbereichs und wäre daher unrein . Die gesamte äußere Funktion ist also rein, die Schleife jedoch nicht. Bei Schleifenkonstrukten in der funktionalen Programmierung müssen Sie den Status explizit angeben. Das Übersetzen Ihres Codes in etwas mit funktionalen Programmierschleifenwerkzeugen zeigt die Unreinheit:

int as_int(char *str)
{
    int acc = 0; /* accumulate the partial result */

    map(takeWhile(isdigit, str), void function(char *chr) {
      acc = acc * 10 + (chr - '0');
    });

    return acc;
}

(Hinweis - Diese Syntax ist ungefähr, um die allgemeine Vorstellung zu vermitteln.)

Dieser Code verwendet eine innere Funktion für den Schleifenkörper, die die Variable mutieren muss acc, die außerhalb ihres Gültigkeitsbereichs liegt. Dies ist unrein - die Funktion der inneren Schleife hängt vom Kontext der äußeren Schleife ab . Wenn Sie sie mehrmals mit demselben Zeichen aufrufen, hat dies Nebenwirkungen, und die Reihenfolge, in der Sie sie in der Reihenfolge der Zeichen aufrufen, ist von Bedeutung. Um dies in der funktionalen Programmierung zu einer reinen Funktion zu machen, müssten Sie diese Abhängigkeit vom Zustand, der zwischen Schleifeniterationen übergeben wird, explizit machen mit fold:

int as_int(char *str)
{
    return fold(takeWhile(isdigit, str), 0, int function(char *chr, int acc) {
      return acc * 10 + (chr - '0');
    });
}

foldverwendet eine Funktion von zwei Argumenten für den inneren Schleifenkörper: Das erste Argument ist ein Element in der Sequenz, die foldeine Schleife durchläuft, während das zweite ein Wert ist, den der innere Schleifenkörper verwendet, um Teilergebnisse aufzubauen. Für die erste Schleifeniteration accist 0, für die zweite accist alles , was der erste Aufruf der inneren Schleifenfunktion zurückgegeben hat, für die dritte ist es, was auch immer die zweite innere Schleife zurückgegeben hat, und die letzte Schleife gibt das Ergebnis des gesamten foldAusdrucks zurück.

Beachten Sie, dass dies aus Sicht des restlichen Programms kein wirkliches Problem mit Ihrem Code darstellt - beide Definitionen von as_intsind rein. Der Unterschied besteht darin, dass Sie den Code der inneren Schleife zu einer reinen Funktion machen. Sie können die zahlreichen Tools nutzen, die die funktionale Programmierung bietet, um die Schleife in etwas Deklarativeres zu zerlegen (z. B. mithilfe von takeWhile, fold, filter, map usw. usw.).


6
+1. Zu den Vorteilen der höherwertigen Funktionen wie takeWhile, fold, filter, map, (dh deklarativen Stil) ist , dass Sie auch Stop - Denken in Bezug auf die „Compute etwas von destruktiv Aktualisierung Speicherplätze“. Auf diese Weise hängt das Ergebnis nicht von der Historie / genauen Reihenfolge der Berechnungsschritte ab.
Giorgio
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.