Digamos que temos uma função pura normal, como
function add(a, b) {
return a + b
}
E então nós a alteramos para que tenha um efeito colateral
function add(a, b) {
writeToDatabase(Math.random())
return a + b;
}
Até onde eu sei, não é considerada uma função pura, porque muitas vezes ouço as pessoas chamarem funções puras de "funções sem efeitos colaterais". No entanto, ele se comporta como uma função pura na medida em que retornará a mesma saída para as mesmas entradas.
Existe um nome diferente para esse tipo de função, ele não tem nome ou ainda é realmente puro e estou enganado sobre a definição de pureza?
writeToDatabase
falhar, isso poderá desencadear uma exceção, fazendo com que sua segundaadd
função produza uma exceção às vezes, mesmo se chamada com os mesmos argumentos que antes não apresentavam problemas ... na maioria das vezes, os efeitos colaterais introduzem esse tipo de condições relacionadas a erros que quebram "pureza de entrada e saída".F(x)
é definido para retornartrue
se for chamado com o mesmo argumento da chamada anterior. Claramente com a sequência{1,2,2} => {undefined, false, true}
isso é determinístico, mas fornece resultados diferentes paraF(2)
.Respostas:
Não tenho certeza sobre as definições universais de pureza, mas do ponto de vista de Haskell (uma linguagem em que os programadores tendem a se preocupar com coisas como pureza e transparência referencial), apenas a primeira de suas funções é "pura". A segunda versão do
add
não é pura . Então, em resposta à sua pergunta, eu chamaria de "impura";)De acordo com esta definição, uma função pura é uma função que:
Com essa definição, fica claro que sua segunda função não pode ser considerada pura, pois quebra a regra 2. Ou seja, os dois programas a seguir NÃO são equivalentes:
e
Isso ocorre porque, embora ambas as funções retornem o mesmo valor, a função
f
gravará no banco de dados duas vezes, masg
gravará uma vez! É muito provável que as gravações no banco de dados façam parte do comportamento observável do seu programa. Nesse caso, mostrei que sua segunda versão doadd
"não é" pura.Se as gravações no banco de dados não são uma parte observável do comportamento do seu programa, as duas versões
add
podem ser consideradas equivalentes e puras. Mas não consigo pensar em um cenário em que a gravação no banco de dados não importe. Até o registro é importante!fonte
f(x)
depende não apenas dex
, mas também de alguma variável global externay
. Então, sef
tiver a propriedade de RT, você poderá trocar livremente todas as ocorrências com seu valor de retorno , desde que não toquey
. Sim, meu exemplo é duvidoso. Mas o importante é: sef
gravar no banco de dados (ou gravar em um log), perderá a propriedade do RT: agora não importa se você deixa o mundoy
intocado, você sabe que o significado do seu programa muda dependendo de você realmente liguef
ou simplesmente use seu valor de retorno.Essa função é chamada
Em relação ao estado:
Dependendo de qual definição de uma função você usa, uma função não tem estado. Se você vem do mundo orientado a objetos, lembre-se de que
x.f(y)
é um método. Em função, seria semelhantef(x,y)
. E se você gosta de fechamentos com escopo lexical fechado, lembre-se de que o estado imutável também pode fazer parte da expressão das funções. É apenas um estado mutável que afetaria a natureza determinística das funções. Portanto, f (x) = x + 1 é determinístico desde que o 1 não mude. Não importa onde o 1 está armazenado.Suas funções são determinísticas. Seu primeiro também é uma função pura. Seu segundo não é puro.
O ponto 1 significa determinístico . O ponto 2 significa transparência referencial . Juntos, eles significam que uma função pura apenas permite que seus argumentos e seu valor retornado sejam alterados. Nada mais causa mudanças. Nada mais mudou.
fonte
Math.random()
. Portanto, não, a menos que assumamos um PRNG (em vez de um RNG físico) E consideremos que os PRNGs indicam parte da entrada (o que não é, a referência é codificada), não é determinístico.Se você não se importa com o efeito colateral, é referencialmente transparente. É claro que é possível que você não se importe, mas alguém o faça, então a aplicabilidade do termo depende do contexto.
Não conheço um termo geral para exatamente as propriedades que você descreve, mas um subconjunto importante são aquelas que são idempotentes . Na ciência da computação, um pouco diferente da matemática *, uma função idempotente é aquela que pode ser repetida com o mesmo efeito; isto é, o bom efeito colateral de fazê-lo muitas vezes é o mesmo de fazê-lo uma vez.
Portanto, se seu efeito colateral fosse atualizar um banco de dados com um determinado valor em uma determinada linha ou criar um arquivo com conteúdo exatamente consistente, seria idempotente , mas se adicionado ao banco de dados ou anexado a um arquivo , então não faria.
Combinações de funções idempotentes podem ou não ser idempotentes como um todo.
* O uso de idempotente de maneira diferente na ciência da computação e na matemática parece ter resultado de um uso incorreto do termo matemático que foi então adotado porque o conceito é útil.
fonte
(f x, f x)
porlet y = f x in (y, y)
ficará sem espaço em disco - exceções duas vezes mais rápido que você poderia argumentar casos extremos com os quais você não se importa, mas com uma definição tão confusa, podemos chamar denew Random().Next()
referencialmente transparente, porque diabos, eu não me importo com o número que recebo.Random.Next
no .NET realmente tem efeitos colaterais. Muito mesmo. Se puderNext
, atribua-o a uma variável e, em seguida, ligueNext
novamente e atribua-o a outra variável, é provável que não sejam iguais. Por quê? Porque invocarNext
altera algum estado interno oculto noRandom
objeto. Esse é o oposto polar da transparência referencial. Não entendo sua alegação de que "efeitos principais" não podem ser efeitos colaterais. No código imperativo, é mais comum do que não que o efeito principal seja um efeito colateral, porque os programas imperativos são stateful por natureza.Eu não sei como essas funções são chamadas (ou se existe algum nome sistemático), mas eu chamaria uma função que não é pura (como outras respostas se escondem), mas sempre retorna o mesmo resultado se fornecida com os mesmos parâmetros "função de sua parâmetros "(em comparação com a função de seus parâmetros e algum outro estado). Eu chamaria isso apenas de função, mas, infelizmente, quando dizemos "função" no contexto da programação, queremos dizer algo que não precisa ser uma função real.
fonte
Depende basicamente de você se importar ou não com a impureza. Se a semântica desta tabela é que você não se importa com quantas entradas existem, então é pura. Senão, não é puro.
Ou, em outras palavras, tudo bem, desde que as otimizações baseadas na pureza não quebrem a semântica do programa.
Um exemplo mais realista seria se você estivesse tentando depurar essa função e adicionasse instruções de log. Tecnicamente, o log é um efeito colateral. Os logs tornam impuro? Não.
fonte
Eu diria que a melhor coisa a se perguntar não é como o chamaríamos, mas como analisaríamos esse pedaço de código. E minha primeira pergunta-chave nessa análise seria:
Isso é simples de ilustrar em Haskell (e essa frase é apenas meia piada). Um exemplo do caso "não" seria algo como isto:
Neste exemplo, a ação que executamos (imprime a linha
"I'm doubling some number"
) não afeta a relação entrex
e o resultado. Isso significa que podemos refatorá-lo dessa maneira (usando aApplicative
classe e seu*>
operador), o que mostra que a função e o efeito são de fato ortogonais:Então, neste caso, eu pessoalmente diria que é um caso em que você pode fatorar uma função pura. Muita programação de Haskell trata disso - aprendendo a fatorar as partes puras a partir do código eficaz.
Um exemplo do tipo "yes", em que as partes pura e eficaz não são ortogonais:
Agora, a sequência impressa depende do valor de
x
. A parte da função (multiplicadax
por dois), no entanto, não depende do efeito, portanto ainda podemos fatorá-la:Eu poderia continuar explicando outros exemplos, mas espero que isso seja suficiente para ilustrar o ponto em que comecei: você não "chama" isso de algo, analisa como as partes puras e eficazes se relacionam e as fatora quando é necessário. para sua vantagem.
Essa é uma das razões pelas quais a Haskell usa sua
Monad
classe tão extensivamente. Mônadas são (entre outras coisas) uma ferramenta para realizar esse tipo de análise e refatoração.fonte
As funções que se destinam a causar efeitos colaterais geralmente são chamadas de eficazes . Exemplo https://slpopejoy.github.io/posts/Effectful01.html
fonte