Como você chama uma função em que a mesma entrada sempre retornará a mesma saída, mas também tem efeitos colaterais?

39

Digamos que tenhamos uma função pura normal, como

function add(a, b) {
  return a + b
}

E então nós alteramos de tal forma que ele tenha um efeito colateral

function add(a, b) {
  writeToDatabase(Math.random())
  return a + b;
}

Não é considerado uma função pura, tanto quanto eu sei, porque muitas vezes eu ouço as pessoas chamam funções puras de "funções sem efeitos colaterais". No entanto, ele se comporta como uma função pura, no que diz respeito ao fato de que ele retornará a mesma saída para as mesmas entradas.

Existe um nome diferente para este tipo de função, é sem nome, ou ainda é realmente puro e eu estou enganado sobre a definição de pureza?

    
por m0meni 30.04.2016 / 23:21
fonte

7 respostas

83

Não tenho certeza sobre definições universais de pureza, mas do ponto de vista do Haskell (uma linguagem em que os programadores tendem a se importar com coisas como pureza e transparência referencial), somente a primeira das suas funções é "puro". A segunda versão do add não é pura . Então, em resposta à sua pergunta, eu chamaria de "impuro";)

De acordo com esta definição, uma função pura é uma função que:

  1. Depende apenas da sua entrada. Isto é, dada a mesma entrada, sempre retornará a mesma saída.
  2. É referencialmente transparente: a função pode ser livremente substituída por seu valor e o "comportamento" do programa não será alterado.

Com esta definição, fica claro que sua segunda função não pode ser considerada pura, já que quebra a regra 2. Ou seja, os dois programas a seguir NÃO são equivalentes:

function f(a, b) { 
    return add(a, b) + add(a, b);
}

e

function g(a, b) {
    c = add(a, b);
    return c + c;
}

Isso ocorre porque, mesmo que ambas as funções retornem o mesmo valor, a função f gravará no banco de dados duas vezes, mas g 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 do add não é "pura".

Se as gravações no banco de dados não forem uma parte observável do comportamento do seu programa, as duas versões de add poderão ser consideradas equivalentes e puras. Mas não consigo pensar em um cenário em que escrever no banco de dados não tenha importância. Até mesmo questões de registro!

    
por 01.05.2016 / 00:21
fonte
19

What do you call a function [for which] the same input will always return the same output, but also has side effects?

Essa função é chamada

deterministic

An algorithm whose behavior can be completely predicted from the input.

termwiki.com

Em relação ao estado:

Dependendo da definição de uma função que 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. Como função, seria parecido com f(x,y) . E se você estiver em encerramentos com escopo léxico fechado, lembre-se de que o estado imutável pode muito bem fazer parte da expressão de funções. É apenas um estado mutável que teria impacto na natureza determinista das funções. Então f (x) = x + 1 é determinista, 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.

Pure function

  1. The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change while program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices.

  2. Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices.

wikipedia.org

O ponto 1 significa determinista . O ponto 2 significa transparência referencial . Juntos, eles significam que uma função pura permite apenas que seus argumentos e seu valor retornado mudem. Nada mais provoca mudanças. Nada mais é alterado.

    
por 02.05.2016 / 15:17
fonte
8

Se você não se importa com o efeito colateral, então é referencialmente transparente. É claro que é possível que você não se importe, mas alguém o faz, então a aplicabilidade do termo depende do contexto.

Eu não sei de um termo geral para as propriedades que você descreve, mas um subconjunto importante são aquelas que são idempotentes . Em ciência da computação, um pouco diferente de em matemática *, uma função idempotente é aquela que pode ser repetida com o mesmo efeito; isto é, o resultado de efeito colateral de muitas vezes é o mesmo de fazê-lo uma vez.

Então, se o seu efeito colateral foi atualizar um banco de dados com um determinado valor em uma determinada linha, ou criar um arquivo com conteúdo exatamente consistente, então ele seria idempotente , mas se adicionado ao banco de dados, ou anexado a um arquivo, então não seria.

Combinações de funções idempotentes podem ou não ser idempotentes como um todo.

* O uso de idempotente de forma diferente na ciência da computação parece ter vindo de um uso incorreto do termo matemático que foi adotado porque o conceito é útil.

    
por 01.05.2016 / 14:32
fonte
3

Eu não sei como tais funções são chamadas (ou se há algum nome sistemático), mas eu chamaria função que não é pura (como outras respostas acovardadas) mas sempre retorna o mesmo resultado se fornecido com os mesmos parâmetros " função de seus 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 tem que ser uma função real.

    
por 01.05.2016 / 01:02
fonte
2

Depende basicamente de se você se importa 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. Mais, não é puro.

Ou, para colocar de outra forma, tudo bem, desde que as otimizações baseadas na pureza não interrompam a semântica do programa.

Um exemplo mais realista seria se você estivesse tentando depurar essa função e adicionasse instruções de registro. Tecnicamente, o registro é um efeito colateral. Os logs tornam impuro? Não.

    
por 30.04.2016 / 23:36
fonte
1

Eu diria que a melhor coisa a fazer não é como poderíamos chamá-lo, mas como poderíamos analisar esse pedaço de código. E minha primeira pergunta-chave em tal análise seria:

  • O efeito colateral depende do argumento da função ou do resultado do efeito colateral?
    • Não: A "função efetiva" pode ser refatorada em uma função pura, uma ação efetiva e um mecanismo para combiná-las.
    • Sim: A "função efetiva" é uma função que produz um resultado monádico.

Isso é fácil de ilustrar em Haskell (e essa frase é apenas meia piada). Um exemplo do caso "não" seria algo assim:

double :: Num a => a -> IO a
double x = do
  putStrLn "I'm doubling some number"
  return (x*2)

Neste exemplo, a ação que tomamos (imprimir a linha "I'm doubling some number" ) não afeta a relação entre x e o resultado. Isso significa que podemos refatorar dessa forma (usando a classe Applicative e seu operador *> ), o que mostra que a função e o efeito são de fato ortogonais:

double :: Num a => a -> IO a
double x = action *> pure (function x)
  where
    -- The pure function 
    function x = x*2  
    -- The side effect
    action = putStrLn "I'm doubling some number"

Então, neste caso, eu pessoalmente diria que é um caso em que você pode fatorar uma função pura. Muito da programação de Haskell é sobre isso - aprender a fatorar as partes puras do código efetivo.

Um exemplo do tipo "sim", em que as partes pura e eficaz não são ortogonais:

double :: Num a => a -> IO a
double x = do
  putStrLn ("I'm doubling the number " ++ show x)
  return (x*2)

Agora, a string que você imprime depende do valor de x . A função (multiplique x por dois), no entanto, não depende do efeito, então ainda podemos fatorar:

logged :: (a -> b) -> (a -> IO x) -> IO b
logged function logger a = do
  logger a
  return (function a)

double x = logged function logger
  where function = (*2) 
        logger x putStrLn ("I'm doubling the number " ++ show x)

Eu poderia escrever outros exemplos, mas espero que isso seja suficiente para ilustrar o ponto em que comecei: você não "chama" algo, você analisa como as partes puras e eficazes se relacionam e as considera quando é a sua vantagem.

Esta é uma das razões pelas quais o Haskell usa sua classe Monad tão extensivamente. As mônadas são (entre outras coisas) uma ferramenta para realizar esse tipo de análise e refatoração.

    
por 10.05.2016 / 20:36
fonte
-3

Funções que se destinam a causar efeitos colaterais são geralmente chamadas de efetivas . Exemplo de link

    
por 02.05.2016 / 11:00
fonte