A programação funcional inclui muitas técnicas diferentes. Algumas técnicas são boas com efeitos colaterais. Mas um aspecto importante é o raciocínio equacional : se eu chamo uma função com o mesmo valor, sempre obtenho o mesmo resultado. Portanto, posso substituir uma chamada de função pelo valor de retorno e obter um comportamento equivalente. Isso facilita o raciocínio sobre o programa, especialmente durante a depuração.
Caso a função tenha efeitos colaterais, isso não se aplica. O valor de retorno não é equivalente à chamada da função, porque o valor de retorno não contém os efeitos colaterais.
A solução é parar de usar efeitos colaterais e codificá-los no valor de retorno . Idiomas diferentes têm sistemas de efeitos diferentes. Por exemplo, Haskell usa mônadas para codificar certos efeitos, como IO ou mutação de estado. As linguagens C / C ++ / Rust possuem um sistema de tipos que pode impedir a mutação de alguns valores.
Em uma linguagem imperativa, uma print("foo")
função imprimirá algo e não retornará nada. Em uma linguagem funcional pura como Haskell, uma print
função também pega um objeto que representa o estado do mundo exterior e retorna um novo objeto que representa o estado depois de executar essa saída. Algo parecido com newState = print "foo" oldState
. Eu posso criar quantos estados novos quiser do estado antigo. No entanto, apenas um será usado pela função principal. Então, preciso sequenciar os estados de várias ações, encadeando as funções. Para imprimir foo bar
, posso dizer algo como print "bar" (print "foo" originalState)
.
Se um estado de saída não for usado, o Haskell não executará as ações anteriores àquele estado, porque é uma linguagem lenta. Por outro lado, essa preguiça só é possível porque todos os efeitos são explicitamente codificados como valores de retorno.
Observe que Haskell é a única linguagem funcional comumente usada que usa essa rota. Outras linguagens funcionais incl. a família Lisp, a família ML e as linguagens funcionais mais recentes, como Scala, desencorajam, mas permitem efeitos colaterais ainda - elas podem ser chamadas de linguagens funcionais imperativas.
Usar efeitos colaterais para E / S provavelmente é bom. Freqüentemente, a E / S (exceto a criação de log) é feita apenas no limite externo do seu sistema. Nenhuma comunicação externa acontece dentro da sua lógica de negócios. Em seguida, é possível escrever o núcleo do seu software em um estilo puro, enquanto ainda executa E / S impuras em um shell externo. Isso também significa que o núcleo pode ser sem estado.
A apatridia possui várias vantagens práticas, como maior razoabilidade e escalabilidade. Isso é muito popular para back-end de aplicativos da web. Qualquer estado é mantido fora, em um banco de dados compartilhado. Isso facilita o balanceamento de carga: não preciso colar sessões em um servidor específico. E se eu precisar de mais servidores? Basta adicionar outro, porque ele está usando o mesmo banco de dados. E se um servidor travar? Posso refazer qualquer solicitação pendente em outro servidor. Claro, ainda há estado - no banco de dados. Mas eu o expliquei e extraí, e poderia usar uma abordagem funcional pura internamente, se eu quisesse.