2008-11-22 12 views
5

Ich lerne funktionale Programmierung und habe versucht, ein paar Probleme in einem funktionalen Stil zu lösen. Eine Sache, die ich bei der Aufteilung meines Problems in Funktionen erlebte, war, dass ich zwei Möglichkeiten hatte: verschiedene Funktionen mit ähnlichen Parameterlisten zu verwenden oder verschachtelte Funktionen zu verwenden, die sich als Closures einfach auf Bindungen in der Elternfunktion beziehen können.Verschachtelte Funktionen: Falsche Verwendung von Nebenwirkungen?

Obwohl ich mit dem zweiten Ansatz ging, weil es die Funktionsaufrufe kleiner machte und es sich "besser" anfühlte, scheint mir aus meiner Lektüre einer der Hauptpunkte der funktionalen Programmierung darin zu fehlen das scheint "nebenwirkend" zu sein? Diese geschachtelten Funktionen können die äußeren Bindungen nicht ändern, da die Sprache, die ich verwendete, dies verhindert, aber wenn man sich jede einzelne innere Funktion ansieht, kann man nicht sagen: "Bei denselben Parametern liefert diese Funktion die gleichen Ergebnisse" weil sie die Variablen aus dem übergeordneten Bereich verwenden ... habe ich recht?

Was ist der gewünschte Weg?

Danke!

Antwort

2

Nesting-Funktionen sind eine hervorragende Möglichkeit, die Arbeit in vielen Funktionen aufzuteilen. Es ist nicht wirklich "nebenwirkend"; Wenn es hilft, stellen Sie sich die erfassten Variablen als implizite Parameter vor.

Ein Beispiel, wo verschachtelte Funktionen nützlich sind, ist das Ersetzen von Schleifen. Die Parameter der verschachtelten Funktion können als Induktionsvariablen fungieren, die Werte akkumulieren. Ein einfaches Beispiel:

let factorial n = 
    let rec facHelper p n = 
     if n = 1 then p else facHelper (p*n) (n-1) 
    in 
    facHelper 1 n 

In diesem Fall wäre es nicht wirklich Sinn machen, eine Funktion wie facHelper global zu erklären, da die Nutzer nicht über die p Parameter zu kümmern.

Beachten Sie jedoch, dass es schwierig sein kann, geschachtelte Funktionen einzeln zu testen, da sie nicht außerhalb des übergeordneten Objekts aufgeführt werden können.

+0

facHelper bezieht sich nicht auf irgendwelche externen Werte - es ist immer noch rein funktional. –

3

Funktionale Programmierung ist nicht alles oder nichts. Wenn das Verschachteln der Funktionen sinnvoller ist, würde ich mit diesem Ansatz fortfahren. Wenn Sie jedoch wirklich wollen, dass die internen Funktionen rein funktional sind, übergeben Sie explizit alle erforderlichen Parameter an sie.

Hier ist ein kleines Beispiel in Schema:

(define (foo a) 
    (define (bar b) 
    (+ a b))  ; getting a from outer scope, not purely functional 
    (bar 3)) 

(define (foo a) 
    (define (bar a b) 
    (+ a b))  ; getting a from function parameters, purely functional 
    (bar a 3)) 


(define (bar a b) ; since this is purely functional, we can remove it from its 
    (+ a b))  ; environment and it still works 

(define (foo a) 
    (bar a 3)) 

Ich persönlich gehen würde mit dem ersten Ansatz, aber entweder gleich gut funktionieren.

1

Betrachten Sie den folgenden (erfundenen) Haskell-Schnipsel:

putLines :: [String] -> IO() 
putLines lines = putStr string 
    where string = concat lines 

string ist ein lokal benannte Konstante gebunden ist. Aber ist es nicht auch eine Funktion, die keine Argumente nimmt, die über lines schließt und daher referentiell intransparent ist? (In Haskell sind Konstanten und Nullfunktionen in der Tat nicht unterscheidbar!) Würden Sie den obigen Code als "nebenwirkungsfrei" oder nicht funktionierend betrachten?

Verwandte Themen