Getters y Setters en lenguajes funcionales

9

Uno de los principios de la programación funcional es el uso de funciones puras. Una función pura es aquella que no tiene efectos secundarios y es referencialmente transparente.

Los getters no son referencialmente transparentes: si se llama a un Setter entre llamadas al Getter, el valor de retorno del Getter cambia aunque sus parámetros no lo hayan hecho (normalmente no hay parámetros)

Los setters producen efectos secundarios: llamar a un setter normalmente manipula un valor que no es su valor de retorno (de hecho, tradicionalmente un setter no devuelve nada)

Sé que en Scala simplemente aceptamos el hecho de que estamos combinando dos paradigmas (funcionales y orientados a objetos) y usamos getters / setters como lo haríamos en un lenguaje como Java.

En un lenguaje como Haskell (con el que no soy fluido, pero me dicen que es más cierto que un lenguaje funcional "Puro") tengo curiosidad por saber cómo modelaría propiedades en objetos de modo que los Getters sean referencialmente transparentes y Setters son libres de efectos secundarios?

¿Sería la solución devolver una copia del objeto sobre el que se invocó al establecedor como el valor de retorno del establecedor, y esta copia contiene el cambio al valor de la propiedad?

ThaDon
fuente
8
Los captadores y establecedores tienen el objeto como parámetro, aunque generalmente es implícito, por lo que los captadores son referencialmente transparentes.
@delnan, solo si el atributo que está leyendo es inmutable.
dan_waterworth
3
@dan_waterworth: Solo si leemos el "mismo" en "referencialmente transparente" como identidad de objeto. Si el hecho de que el atributo subyacente es diferente lo convierte en una llamada con diferentes argumentos (que está en línea con la mayoría de las definiciones de igualdad). Esto es ignorar otro hilo que llama a un setter y terminarlo entre la llamada al getter y el getter que finaliza, pero en ese caso tienes problemas más serios de todos modos.

Respuestas:

7

Exactamente. Ver método de clase de caso copy, o el concepto general de lentes.

En particular, si el estado necesita un cambio, usaría una mónada estatal. Los cambios a esa mónada de estado se pueden hacer a través de lentes, lo que hace que extraer información del "estado" y cambiarlo sea fácil.

Vea también esta pregunta sobre el problema general que proviene de una estructura profunda como "estado" y hacer cambios en él. Las respuestas tienen buenos enlaces tanto en lentes como en cremalleras si quieres profundizar en eso.

Daniel C. Sobral
fuente
Pregunta Daniel: ¿hay alguna razón particular por la que copy () esté vinculado a las clases de Case? Esto no parece específico para las necesidades (palabra equivocada, pero no se me ocurre otra) de las clases Case específicamente, parece (para mí) más una característica adecuada para todas las clases. ¿Qué sucede si necesito copy () en mi clase sin caso? ¿Hay algún rasgo que pueda usar para obtener esa funcionalidad?
ThaDon
1
Se supone que las clases de casos de @ThaDon están definidas por sus parámetros de constructor: su igualdad, código hash y extractor se basan en esta suposición, y también el método de copia. En las clases sin mayúsculas y minúsculas, nadie sabe si los parámetros del constructor son todo lo que se necesita para copiar una clase. Sin embargo, puede escribir fácilmente su propio método de copia.
Daniel C. Sobral
11

Bueno, en Haskell, los objetos son (generalmente) inmutables, por lo que los captadores (que se obtienen cuando se usa la sintaxis de registro) o las funciones que actúan como captadores son referencialmente transparentes. Y luego no "establece" valores en los objetos; en todo caso, crea un nuevo objeto que es similar al anterior, pero con un valor diferente para uno de los campos. Esta también es una función pura.

MatrixFrog
fuente
1
"los objetos son (generalmente) inmutables" cuando no lo son?
Sara
-1

"Los captadores y establecedores tienen el objeto como parámetro, aunque generalmente es implícito, por lo que los captadores son referencialmente transparentes. - delnan"

Referencialmente transparente significa que la función SIEMPRE devuelve la misma salida para las mismas entradas; entonces, si un setter ha cambiado un atributo de objeto, no está devolviendo el mismo resultado. :)

Casey Hawthorne
fuente
Pero, si un setter cambió el objeto, la entrada al getter (es decir, el argumento propio implícito) HA cambiado.
Stephen C. Steel
1
El valor / puntero de referencia del objeto no ha cambiado a menos que el objeto se haya movido en el montón.
Casey Hawthorne
55
Sí, pero lógicamente, la entrada implícita es el objeto en sí, no el valor del puntero.
Stephen C. Steel
"si un setter ha cambiado un atributo de objeto, no está devolviendo el mismo resultado": en términos funcionales, ha destruido el primer objeto y ha creado uno nuevo. Por razones de rendimiento (evite copiar y actualizar referencias del objeto antiguo al nuevo) está almacenando el nuevo objeto en la misma área de memoria que contenía el objeto antiguo.
Giorgio