Getters e Setters em idiomas funcionais

9

Um dos princípios da programação funcional é o uso de funções puras. Uma função Pure é aquela que é livre de efeitos colaterais e é referencialmente transparente.

Os Getters não são referencialmente transparentes - se um Setter é chamado entre as chamadas para o Getter, o valor de retorno do Getter muda mesmo que seus parâmetros não (normalmente nenhum parâmetro)

Os setters produzem efeitos colaterais - chamar um setter normalmente manipula um valor que não é seu valor de retorno (na verdade, tradicionalmente, um setter não retorna nada)

Eu sei que em Scala nós apenas aceitamos o fato de estarmos juntando dois paradigmas (funcional e orientado a objetos) e usamos getters / setters como faríamos em uma linguagem como Java.

Em uma linguagem como Haskell (com a qual eu não sou fluente, mas me dizem que é mais fiel a uma linguagem funcional "Pura"), estou curioso para saber como você modelaria propriedades em objetos de forma que Getters sejam referencialmente transparentes e Setters são livres de efeitos colaterais?

A solução seria devolver uma cópia do objeto no qual o setter foi chamado como o valor de retorno do setter, e essa cópia contém a alteração no valor da propriedade?

ThaDon
fonte
8
Getters e setters têm o objeto como parâmetro - mesmo que geralmente esteja implícito -, portanto, os getters são referencialmente transparentes.
@ delnan, apenas se o atributo que está lendo for imutável.
dan_waterworth
3
@dan_waterworth: Somente se lermos o "mesmo" em "Referencialmente transparente" como identidade do objeto. Se o fato de o atributo subjacente ser diferente, ele faz uma chamada com argumentos diferentes (o que está de acordo com a maioria das definições de igualdade). Isso está ignorando outro encadeamento que chama um setter e o finaliza entre a chamada para o getter e o final do getter, mas nesse caso você tem problemas mais sérios de qualquer maneira.

Respostas:

7

Exatamente. Veja o método da classe de caso copyou o conceito geral de lentes.

Em particular, se o estado precisar mudar, você usaria uma mônada do estado. Alterações nessa mônada de estado podem ser feitas através de lentes, o que facilita a extração de informações do "estado" e a alteração fácil.

Veja também esta pergunta sobre o problema geral que vem de uma estrutura profunda como "estado" e faz alterações nele. As respostas têm bons links nas lentes e nos zíperes, se você quiser se aprofundar nisso.

Daniel C. Sobral
fonte
Pergunta Daniel: existe algum motivo específico para que copy () esteja vinculado às classes Case? Isso não parece específico para as necessidades (palavra errada, mas não consigo pensar em outra) das classes Case especificamente, parece (para mim) mais um recurso adequado para todas as classes. E se eu precisar de copy () na minha classe que não seja de caso? Existe uma característica que eu possa usar para obter essa funcionalidade?
ThaDon 28/07
11
As classes de caso @ThaDon devem ser definidas por seus parâmetros de construtor - sua igualdade, código de hash e extrator são baseados nessa suposição, assim como o método de cópia. Em classes que não são casos, ninguém sabe se os parâmetros do construtor são tudo o que é necessário para copiar uma classe. No entanto, você pode escrever facilmente seu próprio método de cópia.
Daniel C. Sobral
11

Bem, em Haskell, os objetos são (geralmente) imutáveis; portanto, os getters (que você obtém ao usar a sintaxe do registro) ou as funções que agem como getters são referencialmente transparentes. E então você não "define" valores nos objetos - se criar algo novo, semelhante ao antigo, mas com um valor diferente para um dos campos. Essa também é uma função pura.

MatrixFrog
fonte
11
"objetos são (geralmente) imutáveis" quando não são?
Sara
-1

"Getters e setters têm o objeto como parâmetro - mesmo que geralmente esteja implícito -, portanto, getters são referencialmente transparentes. - delnan"

Referencialmente transparente significa que a função SEMPRE retorna a mesma saída para as mesmas entradas; portanto, se um atributo de objeto tiver sido alterado por um setter, você não retornará a mesma saída. :)

Casey Hawthorne
fonte
Mas, se o objeto foi alterado por um setter, a entrada para o getter (ou seja, o auto argumento implícito) foi alterado.
Stephen C. Steel
11
O valor / ponteiro de referência do objeto não mudou, a menos que o objeto tenha sido movido no heap.
Casey Hawthorne
5
Sim, mas logicamente, a entrada implícita é o próprio objeto, não o valor do ponteiro.
Stephen C. Steel
"se um atributo de objeto foi alterado por um setter, você não está retornando a mesma saída": Em termos funcionais, você destruiu o primeiro objeto e criou um novo. Por motivos de desempenho (evite copiar e atualizar referências do objeto antigo para o novo), você está armazenando o novo objeto na mesma área de memória que continha o objeto antigo.
Giorgio