Programmazione funzionale per effetto collaterale

7

Sto cercando di capire perché avere una variabile locale o un ciclo for all'interno di una funzione non è considerata pura programmazione funzionale.

Data questa funzione:

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

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

    return acc;
}

In quali circostanze la variabile acc è un effetto collaterale? Anche in un ambiente concorrente ogni invocazione della funzione avrebbe una sua copia di acc. Quindi non capisco perché non è permesso nella programmazione funzionale.

    
posta tomatoRadar 24.12.2014 - 12:24
fonte

1 risposta

11

Il looping nella programmazione funzionale non viene eseguito con istruzioni di controllo come for e while , è fatto con chiamate esplicite a funzioni come map , fold o ricorsione - tutte operazioni che prevedono il posizionamento del ciclo interno chiama all'interno di un'altra funzione . Se il codice di loop muta le variabili al di fuori del ciclo, questa funzione del ciclo interno manipolerebbe le variabili al di fuori del suo ambito e sarebbe quindi impura . Quindi l'intera funzione esterna è pura, ma il ciclo non lo è. I costrutti ciclici nella programmazione funzionale richiedono che lo stato sia esplicito. Tradurre il tuo codice in qualcosa usando gli strumenti di ciclo di programmazione funzionale rivela l'impurità:

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;
}

(Nota: questa sintassi è approssimativa per far passare l'idea generale)

Questo codice usa una funzione interna per il corpo del ciclo che deve mutare la variabile acc , che è al di fuori del suo ambito. Questo è impuro - la funzione del ciclo interno dipende dal contesto del ciclo esterno , chiamandola più volte con lo stesso carattere avrà effetti collaterali e l'ordine che si chiama sulla sequenza di caratteri è importante. Nella programmazione funzionale, al fine di rendere questa una funzione pura, dovresti rendere questa dipendenza dallo stato passato tra iterazioni di loop esplicite con fold :

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

fold utilizza una funzione di due argomenti per il corpo del ciclo interno: il primo argomento è un elemento nella sequenza in cui fold esegue il looping, mentre il secondo è un valore che il corpo del ciclo interno utilizza per creare risultati parziali. Per la prima iterazione del ciclo, acc è 0, per il secondo, acc è qualunque sia la prima chiamata di funzione del ciclo interno restituita, per il terzo, è qualunque sia il secondo ciclo interno restituito e il ciclo finale restituisce il risultato del % espressione fold .

Nota che questo non è un problema con il tuo codice dal punto di vista del resto del tuo programma - entrambe le definizioni di as_int sono pure. La differenza sta nel fatto che il codice del ciclo interno è una funzione pura, è possibile sfruttare la vasta gamma di strumenti offerti dalla programmazione funzionale per scomporre il ciclo in qualcosa di più dichiarativo (ad esempio utilizzando takeWhile, fold, filter, map, ecc. Ecc.)

    
risposta data 24.12.2014 - 14:07
fonte

Leggi altre domande sui tag