Por que é bom não confiar na mudança de estado?

16

Esta questão surge da questão /software/25569/is-haskell-worth-learning

Geralmente, algumas declarações repetidas são feitas, sobre como o Haskell aprimora suas habilidades de codificação em outros idiomas e, além disso, isso ocorre porque o Haskell é apátrida e isso é uma coisa boa.

Por quê?

Vi alguém comparar isso apenas digitando com a mão esquerda, ou talvez fechando os olhos por um dia e apenas confiando no toque. Certamente há mais do que isso?

Está relacionado ao acesso à memória de hardware ou a outra coisa que representa um grande ganho de desempenho?

ocodo
fonte
2
Haskell é acadêmico. Eu assistia a algumas palestras de Rich Hickey sobre Clojure - lá ele faz argumentos pragmáticos matadores (semelhantes aos 3 pontos de Javier, mas também feitos de maneira simples).
Job
2
Sim, consulte clojure.org/state
LennyProgrammers
6
Só porque Haskell é "acadêmico" não significa que seja impraticável ou pragmático.
Tikhon Jelvis

Respostas:

17

há pelo menos três grandes vantagens em cima da minha cabeça:

  1. torna os programas mais próximos das expressões matemáticas. Em matemática, xnão muda, você só não sabe o que é até resolver a equação.

  2. No final, não é mudança de estado (afinal de contas, é assim que o computador funciona em nível baixo); mas está confinado pelo idioma a lugares específicos. isso permite ao compilador grandes oportunidades de mover o código para otimizá-lo, pois sabe que não altera nada do qual outro código dependa.

  3. O código simultâneo não precisa ser sincronizado para acessar dados não alteráveis; portanto, a simultaneidade é aprimorada, tanto nos sistemas de memória compartilhada SMP (todos os sistemas com vários núcleos de hoje) quanto em clusters frouxos.

Javier
fonte
3
Os proponentes da programação funcional enfatizam mais o número 3, ou seja, a execução mais fácil da concorrência.
Mchl
4
@Mchl: Na minha experiência, eles enfatizam "É mais fácil entender e raciocinar", o que corresponde a 1. Embora eu suponha que isso possa diferir entre as comunidades de idiomas.
sepp2k
+1, resposta muito completa. @ sepp2k: ambos são importantes, eu acho. Raciocinar sobre um programa é o que fazemos diariamente, e é verdade que, se você não precisa verificar se o estado não mudou em alguma função profundamente oculta, é muito mais fácil ler apenas métodos de alto nível e entender o que está acontecendo. Em termos de hardware: como estamos avançando cada vez mais em vários processadores e múltiplos núcleos (embora eu ache que levará um tempo até que os computadores domésticos obtenham vários processadores), ter uma linguagem que facilite a programação simultânea é um prêmio.
Matthieu M.
Boa resposta, nº 2, era o que eu supunha ser a resposta e, embora eu tenha lido muitas vezes sobre as vantagens do multiprocessamento, raramente é declarado como um ótimo trabalho.
ocodo
1
No entanto, as linguagens funcionais não são únicas na dependência da coleta de lixo, e a coleta de lixo é muito mais fácil quando você lida com dados imutáveis. Fazer qualquer cálculo em uma arquitetura baseada em instruções significa modificar o estado, o que não significa que as linguagens funcionais sejam de alguma forma mais difíceis de paralelizar. Linguagens funcionais balançam em paralelismo; dados de pesquisa paralelos ao Haskell, é um recurso que seria quase impossível adicionar a uma linguagem imperativa.
dan_waterworth
4

Aqui está outra vantagem: acoplamento reduzido. Se você tiver um código como:

 function doStuff(x) { return x + y;}

e em outro lugar você tem:

 function doOtherStuff(x) { y++; return y + x;}

então as duas funções dependem implicitamente . Não há uma maneira fácil de dizer que a chamada doStuffé afetada pela chamada doOtherStuff. Sem estado mutável, você teria que tornar a conexão explícita.

Obviamente, esse não é um problema com todos os estados mutáveis ​​- o problema é com o estado mutável generalizado. A solução real é ter a imutabilidade por padrão e alguma maneira de "marcar" e restringir o estado mutável para exatamente onde você precisar.

Tikhon Jelvis
fonte
+1. Muitos programadores experientes sabem não escrever código como o descrito acima e não é um grande passo passar de "estado mutável é ruim nesta situação" para "vamos reduzir seriamente a quantidade de estado que mutamos e escrevemos de forma mais funcional", mas é um passo que poucos decepcionam.
dan_waterworth
2

Uma resposta simplificada é: quando você vê um nome em uma linguagem puramente funcional, sabe qual é o valor associado com uma simples pesquisa de sua definição. Se você tiver variáveis ​​mutáveis, poderá saber apenas por qual das várias atribuições foi executada por último, para analisar também o fluxo de controle, que por sua vez pode ser condicional, deixando-o com várias possibilidades. Para obter uma explosão exponencial, você só precisa considerar que o RHS das atribuições é dependente de variáveis; portanto, é necessário analisá-las recursivamente também.

O ponto principal da análise acima é que é insustentável sem comentários explicando a intenção, os invariantes e a semântica: pode ser difícil de interpretar e pode ser difícil verificar se a semântica é respeitada no código real.

Essa resposta é basicamente uma expansão do ponto 1 de @ Javier.

Penso que é também uma explicação da popularidade do regime fraudulento de OO: com OO, o estado mutável é encapsulado, o que facilita muito a análise, localizando as mutações em certa medida e permitindo uma expressão muito mais robusta e verificação da semântica.

Tendo observado isso, a programação funcional não é a resposta. A resposta certa é um sistema que suporta programação indutiva (funcional) e coindutiva (processual), para que as ferramentas certas possam lidar com programação sem estado e com estado. Só que a teoria construtiva (funcional) está bem estabelecida, enquanto a teoria da gestão do estado ainda está em sua infância.

Yttrill
fonte
A combinação de programação funcional e imperativa é exatamente o que Haskell faz - as funções normais são funcionais, enquanto os cálculos com estados podem ser expressos com notações que permitem isolar e controlar cuidadosamente o estado mutável (entre outras coisas). É por isso que a linguagem com a implementação mais prática do STM é Haskell .
Tikhon Jelvis
Do-notation realmente não tem nada a ver com computação stateful per se . A notação de doação é apenas uma sintaxe mais simples sobre os pipelines de função monádica. A computação com estado é apenas uma das coisas que podem ser expressas usando mônadas e, portanto, não-notação.
Jonathan Sterling
Programação funcional e imperativa mista é o que quase toda linguagem existente faz. Haskell pode ter fornecido uma maneira de isolar as partes com estado, mas isso não faz com que seja uma mistura adequada: a caridade é mais como deveria ser (IMHO).
Yttrill
2

Como autor do Siege , um SGBD escrito em Haskell, alguns podem chamar minha opinião de estado mutável em conflito. Espero mostrar o contrário.

O objetivo do estado mutável é descrever o estado atual em que um sistema está. Digamos que você tenha um blog e seja back-end por um banco de dados, o banco de dados descreve as postagens que você possui em seu blog no momento em que você consulta isto. Quantas postagens existem agora?

Compare isso com o estado imutável que é usado para transmitir fatos. Quantas postagens havia no dia 12 de agosto?

Os fatos são fáceis de raciocinar, o estado mutável não é. No entanto, o estado mutável não é algum efeito impuro do mal que deve ser banido do alcance de nossas mentes; muitas vezes precisamos que coexista no mundo mutável em que vivemos, só precisamos usá-lo com mais moderação.

dan_waterworth
fonte