Por que Today () é um exemplo de função impura?

38

Parece que, ao ler algo como este artigo da Wikipedia sobre "funções puras" , elas são listadas Today()como um exemplo de função impura, mas me parece bastante pura. É porque não há argumento formal de entrada? Por que a hora do dia real não é tratada como a "entrada para a função"; nesse caso, se você forneceu a mesma entrada, ou seja, executou today()duas vezes ao mesmo tempo ou viajou de volta no tempo para executá-la novamente (talvez uma hipótese: )), a saída seria ao mesmo tempo. Today()nunca fornece um número aleatório. sempre fornece a hora do dia.

O artigo da Wikipedia diz que "em épocas diferentes ela produzirá resultados diferentes", mas é como dizer que para diferentes x sin(x)fornecerá proporções diferentes. E sin(x)é o exemplo deles de uma função pura.

Brad
fonte
8
Se você passasse na hora do dia, o que a função faria?
JB rei
1
Eu espero que isso lhe dê a hora do dia. (não é a função mais útil). Mas não tem nenhum argumento, que eu acho que é a raiz da resposta.
Brad
3
Você pode prever sua saída (com base nos parâmetros de entrada que você forneceu)?
Daniel B
1
@DanielB Não há poder preditivo para o parâmetro de entrada ausente / nulo que aparece. A única coisa que posso fazer é olhar para o meu relógio de pulso (toque meu celular).
Brad
"Por que a hora do dia real não é tratada como a" entrada para a função "" Este é, basicamente, o problema que as mônadas tentam resolver. As funções puras só podem ser baseadas em suas entradas e não podem ter efeitos colaterais. Se você fizer do "estado do mundo diante de mim" uma entrada e do "estado do mundo depois de mim" como parte do valor de retorno e passar esses estados do mundo através do seu programa, você poderá novamente ser puro.
precisa saber é o seguinte

Respostas:

103

É porque não há argumento formal de entrada?

Isso ocorre porque a saída depende de algo que não é uma entrada, a saber, a hora atual.

Por que a hora do dia real não é tratada como a "entrada para a função"

Porque você não passou como parâmetro. Se você o passasse como parâmetro, a função se tornaria uma função de identidade em datas, o que é bastante inútil. O objetivo de uma Today()função é produzir algo que depende de um valor externo e que muda constantemente (tempo).

A vantagem de funções puras é que seu comportamento é absolutamente reprodutível e determinístico, facilitando a obtenção de provas formais e garantias concretas. Eles sempre fazem a mesma coisa. Today()é praticamente o oposto: sempre (permitindo granularidade de tempo) faz algo diferente.

Michael Borgwardt
fonte
2
Portanto, mesmo que o tempo da realidade seja uma espécie de entrada, porque não é dado como entrada e está fora do controle da função (internamente à função e fora do controle de quem está chamando Today()) Today()torna-se impuro. A Today()função pode ser um exemplo meio bobo. Mais apropriado pode ser alguma Count()função. Dado o mesmo número de itens a serem contados Count(), sempre retornará o mesmo número, mas, como está fora do escopo Count(), é impuro.
Brad
1
@ brad que é um pouco de uma área cinza - há um argumento real implícito - a matriz ou lista. Dada uma lista imutável e o mesmo argumento a cada vez, sempre retornará o mesmo valor.
Max
34
"o tempo da realidade é uma espécie de entrada" - sim; de fato, o estado global está implicitamente disponível (isto é, 'uma espécie de entrada') para todas as funções, mas se elas dependem dele para obter o resultado , são impuras!
precisa saber é
4
@ Brad count()na maioria das linguagens de programação é definitivamente puro. Ele tem um valor de entrada explícito: a coleção cuja contagem você deseja. Não se confunda com uma sintaxe como myCollection.count(); isso é apenas açúcar count(myCollection).
Andrés F.
Ótima resposta, como sempre, mas não cobre explicitamente variáveis ​​livres imutáveis. Eles não são uma entrada para a função - não são passados ​​como parâmetro - mas a função depende deles, mesmo que ainda seja referencialmente transparente.
24

sin(x)sempre retornará o mesmo valor, desde que xpermaneça o mesmo. Today()pode retornar resultados diferentes ao longo do tempo, pois depende de valores fora do seu controle . Por exemplo, se algo fora do controle do seu programa alterar o interno do sistema $current_datetime enquanto o programa estiver em execução, Today()produzirá resultados diferentes repentinamente.

FrustratedWithFormsDesigner
fonte
"sempre retornará um valor diferente" é um pouco ... redação impura . Wikipedia diz: "Retorna o dia da semana atual" o que significa que os valores obtidos nas segundas-feiras não será diferente
mosquito
7
@gnat: Verdade, a menos que algo externo ao seu programa altere o calendário interno do computador, de modo que de repente ele pensou que era quinta-feira. A ligação Today()retornaria "quinta-feira" na segunda-feira.
FrustratedWithFormsDesigner
3
@gnat Bem, nem sempre ele retorna um valor diferente (quase não existe nenhuma função útil que o faça). Mas, como a maioria das funções impuras, o valor de retorno pode variar mesmo durante a execução de um único programa (por exemplo, se for executado da noite para o dia).
3
@ delnan: Sim, essa é a desgraça dos autores ingênuos de scripts de banco de dados! : P "Mas como poderia faltar 300 registros? O script funcionou bem quando eu testei ontem de manhã!"
FrustratedWithFormsDesigner
@ delnan isso é certo. Eu só apontou que o uso de sempre na redacção inicial (corrigido em resposta versão atual para poderiam ) foi um pouco imprecisa
mosquito
13

Today () é uma função impura porque seu resultado depende de algo que você não fornece; especificamente, a hora atual do sistema. Portanto, seu resultado não é determinístico quando baseado apenas nas entradas fornecidas na chamada.

Uma função pura seria int Add(int a, int b) {return a + b;}. A função funciona apenas com o que é fornecido e não usa outros dados de estado externos. O resultado natural disso é que você pode Add(2,2)obter 4 a partir de agora até o final dos tempos. Além disso, como a função não altera nenhum estado externo (não possui "efeitos colaterais"), os Add () 2 e 2 a partir de agora até o final dos tempos não mudarão mais nada no sistema, a menos que você atribua o resultado da função a uma variável ou use o valor para atualizar o estado (que não é uma operação executada pela própria função). Praticamente todas as operações matemáticas clássicas são funções puras e podem ser implementadas como tal.

Hoje (), por outro lado, pode produzir o mesmo valor quando chamado duas vezes seguidas, mas não se for chamado repetidamente por vários dias. Isso ocorre porque depende de dados de estado externo que não são fornecidos por você como parâmetro para a função. Como resultado, é impossível, dentro dos limites do programa, controlar o resultado da função Today (). Ele produzirá um determinado valor em um determinado dia e nunca produzirá esse valor em outro dia, a menos que você altere o relógio do sistema do computador em que é executado (uma alteração geralmente ocorrendo fora dos limites do programa).

Uma função impura não é necessariamente uma coisa ruim; funções impuras são necessárias, mesmo em linguagens funcionais, para interagir com qualquer coisa fora dos limites do programa, como armazenamentos de dados, pipelines de comunicação, monitores da interface do usuário, dispositivos periféricos etc. Um programa que não faz nada disso é um programa isso é fortemente limitado em sua utilidade; Eu chegaria ao ponto de chamar esse programa de trivial, pois, sem meios para aceitar entradas ou meios para informá-lo sobre sua saída, ele poderia estar fazendo nada. Os programas escritos em linguagens funcionais podem ter apenas a entrada fornecida pelo tempo de execução e produzir uma saída relatada ao tempo de execução sem métodos impuros explicitamente definidos, mas isso ocorre porque o tempo de execução está abstraindo todos esses detalhes impuros do trabalho em um sistema de computador imperfeito,

É simplesmente uma coisa muito boa saber quais das funções que você está usando são puras e quais não, para que você possa tomar boas decisões sobre como elas são usadas. Funções impuras, porque fazem coisas ou são dependentes de coisas que não são aparentes em seu uso, podem se comportar de forma imprevisível, dado apenas o conhecimento do uso. É necessário um conhecimento adicional do objetivo da função e, portanto, do que ela precisa ou faz para o estado externo, a fim de colocar um sistema que a use em um estado consistente e, assim, esperar um resultado determinístico.

KeithS
fonte
8

Parece bastante óbvio que essa função falha no primeiro teste de pureza dado no início dessa página:

  1. A função sempre avalia o mesmo valor de resultado, dados os mesmos valores de argumento. O valor do resultado da função não pode depender de nenhuma informação ou estado oculto que possa mudar à medida que a execução do programa prossegue ou entre diferentes execuções do programa, nem pode depender de nenhuma entrada externa de dispositivos de E / S.

Observe que, como não requer argumentos, há apenas um conjunto possível de valores de argumentos - o conjunto vazio. E essa função pode e retorna resultados diferentes para o mesmo 'valor (es) de argumento'.

Além disso, o valor do resultado função não depender de "escondidas ... estado que pode mudar à medida que a execução do programa prossegue". Então, outro fracasso.

AakashM
fonte
@ JörgWMittag Não sei ao certo onde afirmo que uma função sem argumentos não pode retornar um valor.
precisa saber é
Peido de cérebro. Eu li "existe apenas um conjunto possível de valores de retorno ".
Jörg W Mittag
8

() => 1seria uma função pura, pois sempre retorna 1. Today()pode retornar "segunda-feira" ou "terça-feira" ou quase qualquer outro valor.

Outra maneira de pensar é que funções puras não dependem do estado. O mundo é tipicamente considerado estado. Você precisa conhecer o estado da realidade para saber que dia é hoje.

No entanto, você não precisa saber nada de especial sobre o estado do mundo para saber o que sin(x)é. E sempre chamar sin(x)para um dado xretornará o mesmo valor.

Guvante
fonte
Wikipedia diz: "Retorna o dia da semana actual", o que significa que pode voltar segunda, terça etc, mas não "2013/01/23", nem "2013/01/24"
mosquito
7
@gnat: Atualizado, mas a diferença não era realmente material.
Guvante
2

Date(timestamp)seria uma função pura. Por causa de sua idempotência. E porque não haveria efeito colateral.

Today()pode variar o resultado dependendo de quando você o chama. É isso que a torna impura. Não é idempotente. Porém, não tem efeito colateral, mas isso não a torna pura.

Florian Margaine
fonte
2

Aqui está um pequeno pseudo-código que penso ao discutir funções puras

newValue = Function();
while(true)
{
   oldValue = newValue;
   newValue = Function();
   assert( newValue == oldValue );
}

Se isso for executado indefinidamente e nunca puder desencadear a afirmação, é uma função pura. Mais ainda, se você tiver uma função que usa args, faça uma pequena modificação ....

oldValue = Function( importantVariableToYourApp );
newValue = Function( importantVariableToYourApp );
assert( newValue == oldValue );

Se você pode usá-lo após todas as atribuições de variáveis ​​no seu aplicativo, e isso não altera os resultados, e nunca pode falhar na afirmação, é uma função pura.

Drake Clarris
fonte
2

Primeiro, não existe uma função sem argumento (ou uma matriz sem índices ou um mapa sem chaves). É a característica definidora de uma função mapear um ou mais valores de argumento para outro valor.

Portanto, todayou não é uma função, portanto nenhuma função pura. Ou podemos interpretar a sintaxe

today()

um pouco para que isso signifique

today   ()      -- today, applied to the value ()

Em Haskell, por exemplo, isso seria válido:

data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving Show
today :: () -> Day
today () = ....?
main = print (today())

porque existe um tipo () com um único valor ().

A questão é apenas: como todaycalcular o dia da semana, se ele tiver apenas ()? Isso simplesmente não é possível sem a leitura do timer do sistema, diretamente ou através das funções impuras auxiliares.

O timer do sistema é um excelente exemplo para o estado global.

Ingo
fonte
1

O problema today()é que ele pode produzir um resultado diferente se chamado duas ou mais vezes em uma função.

Aqui está um exemplo de código que pode introduzir um erro.

function doSomething(when)
{
     if(today() == when)
     {
           // open a resource or create a temp file.....
     }

     // do some other work

     if(today() == when)
     {
           // close the resource or delete temp file.....
     }
}

É possível no exemplo acima. Que a segunda ifdeclaração não será executada. Mesmo se o primeiro fez. Deixando um recurso em um estado ruim.

Reactgular
fonte
1

Para ser uma função pura, fornecer os mesmos parâmetros deve fornecer o mesmo resultado sempre.

Cada vez que ligamos Today(), estamos fornecendo os mesmos parâmetros (nenhum) e, no entanto, não obtendo necessariamente o mesmo resultado (segunda, terça, etc.).

Zantier
fonte
4
isso parece meramente repetir o argumento apresentado e explicado em uma resposta principal publicada cerca de dois anos atrás. Dificilmente vale a pena esbarrar em uma pergunta de dois anos com conteúdo como esse
gnat
1
Não estou muito familiarizado com o funcionamento da stackexchange, mas percebi que, como isso estava entre as principais perguntas, já havia sido resolvido. No que diz respeito a repetir, lembro de ler na meta que pode ser útil ter várias respostas semelhantes. Sinto que o meu é sucinto e potencialmente útil.
Zantier 03/02