Aprendi a programar principalmente do ponto de vista de OOP (como a maioria de nós, tenho certeza), mas passei muito tempo tentando aprender a resolver problemas da maneira funcional. Tenho uma boa noção de como resolver problemas de cálculo com o FP, mas quando se trata de problemas mais complicados, sempre me pego revertendo à necessidade de objetos mutáveis. Por exemplo, se eu estiver escrevendo um simulador de partículas, desejarei "objetos" de partículas com uma posição mutável para atualizar. Como os problemas inerentemente "com estado" geralmente são resolvidos usando técnicas de programação funcional?
functional-programming
Andrew Martin
fonte
fonte
Respostas:
Os programas funcionais lidam muito bem com o estado, mas exigem uma maneira diferente de vê-lo. Para o seu exemplo de posição, uma coisa a considerar é ter sua posição em função do tempo, em vez de um valor fixo . Isso funciona bem para partículas que seguem um caminho matemático fixo, mas você precisa de uma estratégia diferente para lidar com uma mudança no caminho, como após uma colisão.
A estratégia básica aqui é criar funções que captam um estado e retornam o novo estado . Portanto, um simulador de partículas seria uma função que recebe um número
Set
de partículas como entrada e retorna um novo númeroSet
de partículas após um intervalo de tempo. Depois, basta chamar repetidamente essa função com a entrada definida para o resultado anterior.fonte
Conforme observado por @KarlBielefeldt, a abordagem funcional para esse problema é vê-lo como retornando um novo estado de um estado anterior. As funções em si não contêm nenhuma informação e, portanto, sempre atualizam o estado m para o estado n .
Eu acho que você acha isso ineficiente porque assume que o estado anterior deve ser mantido na memória ao computar o novo estado. Observe que a escolha entre escrever um estado completamente novo ou reescrever o antigo é um detalhe da implementação do ponto de vista de uma linguagem funcional.
Por exemplo, digamos que eu tenha uma lista de um milhão de números inteiros e queira aumentar o décimo em uma unidade. Copiar a lista inteira com um novo número em sua décima posição é um desperdício, você está certo; mas é apenas a maneira conceitual de descrever a operação para o compilador ou intérprete de linguagem. O compilador ou intérprete é livre para pegar a primeira lista e substituir a décima posição.
A vantagem de descrever a operação dessa maneira é que o compilador pode raciocinar sobre a situação em que muitos encadeamentos desejam atualizar a mesma lista em posições diferentes. Se a operação for descrita como "vá para esta posição e sobrescreva o que você encontra", será o programador, e não o compilador, responsável por garantir que as sobrescrições não colidam.
Com tudo isso dito, mesmo em Haskell, existe uma mônada do Estado que ajuda a modelar situações em que "manter o estado" é uma solução mais intuitiva para um problema. Mas observe também alguns problemas que você acha que " inerentemente com estado, como gravar em um banco de dados " têm soluções imutáveis como o Datomic . Isso pode ser surpreendente até você entender que é um conceito, não necessariamente sua realização.
fonte
A inscrição no modelo mental correto ajuda a pensar e gerenciar melhor o estado. Na minha opinião, o melhor modelo mental é o flip book . Depois que você clicar, você entenderá que o FP se apóia fortemente em estruturas de dados persistentes que capturam o estado do mundo e que funções são usadas para fazer a transição desse estado sem nenhuma mutação.
Rich Hickey ilumina essas idéias:
Há outras conversas, mas isso deve levá-lo na direção certa.
fonte
Ao escrever aplicativos grandes e moderadamente grandes, muitas vezes achei útil diferenciar as seções do aplicativo com estado e aquelas sem estado.
As estruturas de classes / dados na seção com estado armazenam os dados do aplicativo e as funções nesta seção funcionam com conhecimento implícito dos dados do aplicativo.
As classes / estruturas / funções de dados na seção sem estado estão lá para suportar os aspectos puramente algorítmicos do aplicativo. Eles não têm conhecimento implícito dos dados do aplicativo. Eles trabalham em uma natureza puramente funcional. As partes com estado do aplicativo podem sofrer alterações de estado como efeito colateral das funções em execução na seção sem estado do aplicativo.
A parte mais difícil é descobrir quais classes / funções colocar na seção sem estado e quais classes / funções colocar na seção com estado e ter a disciplina para colocá-los em arquivos / bibliotecas separados.
fonte