Il modo "normale" di esprimere cosa sia una funzione pura è in termini di trasparenza referenziale . Una funzione è pura se è referenzialmente trasparente .
Trasparenza referenziale , grosso modo, significa che puoi sostituire la chiamata alla funzione con il suo valore di ritorno o viceversa in qualsiasi punto del programma, senza cambiare il significato del programma.
Quindi, ad esempio, se i C printf
fossero referenzialmente trasparenti, questi due programmi dovrebbero avere lo stesso significato:
printf("Hello");
e
5;
e tutti i seguenti programmi dovrebbero avere lo stesso significato:
5 + 5;
printf("Hello") + 5;
printf("Hello") + printf("Hello");
Perché printf
restituisce il numero di caratteri scritti, in questo caso 5.
Diventa ancora più ovvio con le void
funzioni. Se ho una funzione void foo
, allora
foo(bar, baz, quux);
dovrebbe essere lo stesso di
;
Cioè poiché foo
non restituisce nulla, dovrei essere in grado di sostituirlo con nulla senza cambiare il significato del programma.
È chiaro, quindi, che né printf
né foo
sono referenzialmente trasparenti, e quindi nessuno dei due è puro. Infatti, una void
funzione non può mai essere referenzialmente trasparente, a meno che non sia una no-op.
Trovo questa definizione molto più facile da gestire come quella che hai dato. Permette anche di applicarlo a qualsiasi granularità tu voglia: puoi applicarlo a singole espressioni, a funzioni, a interi programmi. Ti permette, ad esempio, di parlare di una funzione come questa:
func fib(n):
return memo[n] if memo.has_key?(n)
return 1 if n <= 1
return memo[n] = fib(n-1) + fib(n-2)
Possiamo analizzare le espressioni che compongono la funzione e concludere facilmente che non sono referenzialmente trasparenti e quindi non pure, poiché utilizzano una struttura dati mutabile, ovvero l' memo
array. Tuttavia, possiamo anche esaminare la funzione e vedere che è referenzialmente trasparente e quindi pura. Questa è talvolta chiamata purezza esterna , cioè una funzione che appare pura al mondo esterno, ma è implementata internamente impura.
Tali funzioni sono comunque utili, perché mentre l'impurità infetta tutto ciò che la circonda, l'interfaccia pura esterna costruisce una sorta di "barriera di purezza", dove l'impurità infetta solo le tre linee della funzione, ma non trapela nel resto del programma . Queste tre righe sono molto più facili da analizzare per la correttezza rispetto all'intero programma.