Una funzione che ottiene un valore da un'altra funzione è considerata pura?


9

Sto cercando di capire un modo per gestire i valori delle variabili predefinite quando si creano funzioni senza effetti collaterali e sono finito con il seguente:

function getDefaultSeparator() {
    return ':';
}

function process(input, separator) {
    var separator = separator || getDefaultSeparator();

    // Use separator in some logic

    return output;
}

Il separatore predefinito verrà utilizzato in altre funzioni e voglio solo definirlo in un posto.

Se questa è una funzione pura, qual è la differenza dal solo usare una costante DEFAULT_SEPARATOR globale?


5
Non c'è alcuna differenza sostanziale, a meno che tu non stia pianificando di utilizzare la funzione come segnaposto per aggiungere qualche logica in seguito.
Robert Harvey,

3
Possibile duplicato di Una funzione è immediatamente impura se accetta una funzione come parametro? . La domanda non è un duplicato esatto, ma la risposta dovrebbe essere la stessa. ("Dipende dalla purezza dell'altra funzione.")
jpmc26

1
L'uso di una costante globale non rende impura una funzione. L'uso di un valore globale che si presume sia costante lo fa.
Chepner,

A proposito, puoi curry process(con ordine dei parametri invertito) e poi specializzare la funzione curry suvar processDefault = process(":")
bob

Risposte:


22

Una funzione che ottiene un valore da un'altra funzione è considerata pura?

Dipende da cosa fa l'altra funzione e da cosa fa la funzione chiamante. L'impurità è contagiosa, la purezza no.

Chiamare una funzione pura non cambia la purezza della funzione chiamante. Chiamare una funzione impura rende automaticamente impura anche la funzione chiamante.

Quindi, nel tuo esempio, dipende dalla purezza della parte che hai lasciato fuori: se questo è puro, allora l'intera funzione è pura.

Se questa è una funzione pura, qual è la differenza dal solo usare una costante DEFAULT_SEPARATOR globale?

Niente. Una funzione che restituisce sempre lo stesso valore è indistinguibile da una costante. In effetti, questo è esattamente il modo in cui le costanti sono modellate in λ-calcolo.


2
"Chiamare una funzione impura rende automaticamente impura anche la funzione di chiamata" Ne sei abbastanza sicuro? AFAICS, chiamare una funzione impura non rende automaticamente impuro il chiamante, anche se farlo potrebbe.
Deduplicatore

2
@Deduplicatore: dipende da quante analisi statiche puoi (essere disturbato). Certo, se c'è una funzione funcche ha effetti collaterali quando si passa in 0, ma non quando si passa in 1, allora si può ragionevolmente dire che sebbene esso funcstesso sia "impuro", una funzione che lo chiama come func(1)(e ignorando il valore restituito, cerchiamo dire) non è necessariamente impuro. La chiamata funcè sufficiente per "contaminare" il chiamante come potenzialmente impuro, ma una funzione contaminata potrebbe in qualche modo dimostrarsi pura dopo tutto. Almeno in javascript, dove puro / impuro non è definito nella lingua.
Steve Jessop,

6

Sì, queste sono entrambe funzioni pure (supponendo che anche la parte elisa sia pura) perché:

  1. Il risultato dipende solo dai parametri.
  2. Non ci sono effetti collaterali.

Si noti che se getDefaultSeparator()non fosse una funzione pura, nessuno dei due sarebbe process()puro.

In Javascript, non esiste alcuna differenza significativa tra l'utilizzo di una funzione pura o una costante ed entrambi possono essere utilizzati da una funzione pura, purché sia ​​evitata la capacità di Javascript di ridefinire le funzioni o alterare i valori delle costanti.

Un concetto chiave dietro le funzioni pure è che potrebbero essere sostituiti con il valore che restituiscono senza influenzare i risultati del programma.


1

Come dicono gli altri, certo, è ancora una pura funzione.

Tuttavia, parliamo dei problemi di progettazione. Hai ragione a provare a fare qualcosa per mantenere il codice DRY, inserendo il valore solo una volta. Inoltre, ciò che penso dovrebbe essere considerato è anche il livello di accoppiamento appropriato.

L'uso di una funzione offre una maggiore flessibilità per modificare l'implementazione, vale a dire che l'approccio della funzione offre un accoppiamento più flessibile rispetto a una variabile globale.

La domanda è se uno ne ha bisogno o no?

Se i consumatori e il provider si trovano nello stesso modulo e il provider è privato del modulo, è difficile sostenere che questo livello di accoppiamento libero sia necessario, a causa del fatto che se il provider richiede l'aggiornamento da una variabile privata a un metodo privato, un semplice refactoring all'interno del modulo può essere applicato contemporaneamente ai consumatori. L'uso di un metodo / funzione prima che sia realmente necessario potrebbe rientrare in YAGNI.

Anche se il consumatore (i) e il fornitore si trovano in moduli diversi, tuttavia i moduli sono sottoposti a versione insieme (ad esempio, si utilizza un minificatore, in modo che i moduli dei consumatori e del fornitore si trovino nello stesso file), potrebbe applicarsi anche YAGNI.

D'altra parte, se, ad esempio, il produttore si trova in una libreria o in un pacchetto API o modulo con versione separata dal / i consumatore / i, l'utilizzo della funzione potrebbe essere appropriato. In tal caso dovremmo considerare la longevità dell'API e principi come OCP.

(In un'altra nota, se il tuo codice ha dimensioni significative, incoraggerei l'uso di moduli con campi e metodi piuttosto che variabili e funzioni globali.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.