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:
- O efeito colateral depende do argumento da função ou do resultado do efeito colateral?
- Não: a "função eficaz" pode ser refatorada em uma função pura, uma ação eficaz e um mecanismo para combiná-los.
- Sim: A "função eficaz" é uma função que produz um resultado monádico.
Isso é simples de ilustrar em Haskell (e essa frase é apenas meia piada). Um exemplo do caso "não" seria algo como isto:
double :: Num a => a -> IO a
double x = do
putStrLn "I'm doubling some number"
return (x*2)
Neste exemplo, a ação que executamos (imprime a linha "I'm doubling some number"
) não afeta a relação entre x
e o resultado. Isso significa que podemos refatorá-lo dessa maneira (usando a Applicative
classe 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. 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:
double :: Num a => a -> IO a
double x = do
putStrLn ("I'm doubling the number " ++ show x)
return (x*2)
Agora, a sequência impressa depende do valor de x
. A parte da função (multiplicada x
por dois), no entanto, não depende do efeito, portanto ainda podemos fatorá-la:
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 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.
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)
.