A maneira "normal" de expressar o que é uma função pura é em termos de transparência referencial . Uma função é pura se for referencialmente transparente .
Transparência referencial , grosso modo, significa que você pode substituir a chamada à função por seu valor de retorno ou vice-versa em qualquer ponto do programa, sem alterar o significado do programa.
Então, por exemplo, se C's printf
fossem referencialmente transparentes, esses dois programas deveriam ter o mesmo significado:
printf("Hello");
e
5;
e todos os programas a seguir devem ter o mesmo significado:
5 + 5;
printf("Hello") + 5;
printf("Hello") + printf("Hello");
Porque printf
retorna o número de caracteres escritos, neste caso 5.
Fica ainda mais óbvio com void
funções. Se eu tenho uma função void foo
, então
foo(bar, baz, quux);
deve ser o mesmo que
;
Ou seja, uma vez que foo
não retorna nada, devo ser capaz de substituí-lo por nada sem alterar o significado do programa.
É claro, então, que nem printf
nem foo
são referencialmente transparentes e, portanto, nenhum deles é puro. Na verdade, uma void
função nunca pode ser referencialmente transparente, a menos que seja um ambiente autônomo.
Acho essa definição muito mais fácil de lidar do que a que você deu. Também permite aplicá-lo em qualquer granularidade desejada: você pode aplicá-lo a expressões individuais, a funções, a programas inteiros. Ele permite que você, por exemplo, fale sobre uma função como esta:
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)
Podemos analisar as expressões que compõem a função e facilmente concluir que não são referencialmente transparentes e, portanto, não puras, uma vez que utilizam uma estrutura de dados mutável, ou seja, o memo
array. No entanto, também podemos olhar para a função e ver que ela é referencialmente transparente e, portanto, pura. Isso às vezes é chamado de pureza externa , ou seja, uma função que parece pura para o mundo exterior, mas é implementada internamente impura.
Essas funções ainda são úteis, porque enquanto a impureza infecta tudo ao seu redor, a interface externa pura constrói uma espécie de "barreira de pureza", onde a impureza infecta apenas as três linhas da função, mas não vaza para o resto do programa . Essas três linhas são muito mais fáceis de analisar quanto à correção do que o programa inteiro.