„Normalnym” sposobem wyrażenia tego, czym jest czysta funkcja , jest referencyjna przezroczystość . Funkcja jest czysta, jeśli jest referencyjnie przezroczysta .
Z grubsza mówiąc, przezroczystość referencyjna oznacza, że w dowolnym momencie programu można zastąpić wywołanie funkcji jej wartością zwracaną lub odwrotnie, bez zmiany znaczenia programu.
Na przykład, jeśli C printf
byłyby referencyjnie przezroczyste, te dwa programy powinny mieć to samo znaczenie:
printf("Hello");
i
5;
a wszystkie poniższe programy powinny mieć to samo znaczenie:
5 + 5;
printf("Hello") + 5;
printf("Hello") + printf("Hello");
Ponieważ printf
zwraca liczbę zapisanych znaków, w tym przypadku 5.
W przypadku funkcji staje się to jeszcze bardziej oczywiste void
. Jeśli mam funkcję void foo
, to
foo(bar, baz, quux);
powinien być taki sam jak
;
To znaczy, ponieważ foo
nic nie zwraca, powinienem być w stanie zastąpić to niczym bez zmiany znaczenia programu.
Jest więc jasne, że ani, ani printf
nie foo
są referencyjnie przezroczyste, a zatem żadne z nich nie jest czyste. W rzeczywistości void
funkcja nigdy nie może być referencyjnie przezroczysta, chyba że nie jest operacją.
Uważam, że ta definicja jest znacznie łatwiejsza w obsłudze niż ta, którą podałeś. Pozwala również na zastosowanie go w dowolnej szczegółowości: możesz zastosować go do pojedynczych wyrażeń, do funkcji, do całych programów. Pozwala na przykład porozmawiać o takiej funkcji:
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)
Możemy przeanalizować wyrażenia, które składają się na funkcję i łatwo stwierdzić, że nie są one referencyjnie przezroczyste, a zatem nie są czyste, ponieważ używają zmiennej struktury danych, a mianowicie memo
tablicy. Możemy jednak również spojrzeć na funkcję i zobaczyć, że jest ona referencyjnie przezroczysta, a zatem czysta. Nazywa się to czasem czystością zewnętrzną , tj. Funkcją, która wydaje się czysta dla świata zewnętrznego, ale wewnętrznie jest zaimplementowana jako nieczysta.
Takie funkcje są nadal przydatne, ponieważ podczas gdy zanieczyszczenie infekuje wszystko wokół siebie, zewnętrzny czysty interfejs tworzy rodzaj „bariery czystości”, w której zanieczyszczenie infekuje tylko trzy wiersze funkcji, ale nie przedostaje się do reszty programu . Te trzy wiersze są znacznie łatwiejsze do przeanalizowania pod kątem poprawności niż cały program.