En una respuesta a esta pregunta (escrita por Pete) hay algunas consideraciones sobre la POO versus la PF. En particular, se sugiere que los lenguajes FP no son muy adecuados para modelar objetos (persistentes) que tienen una identidad y un estado mutable.
Me preguntaba si esto es cierto o, en otras palabras, cómo se modelarían los objetos en un lenguaje de programación funcional. Desde mi conocimiento básico de Haskell, pensé que uno podría usar mónadas de alguna manera, pero realmente no sé lo suficiente sobre este tema para llegar a una respuesta clara.
Entonces, ¿cómo se modelan normalmente las entidades con una identidad y un estado persistente mutable en un lenguaje funcional?
Aquí hay algunos detalles adicionales para aclarar lo que tengo en mente. Tome una aplicación Java típica en la que pueda (1) leer un registro de una tabla de base de datos en un objeto Java, (2) modificar el objeto de diferentes maneras, (3) guardar el objeto modificado en la base de datos.
¿Cómo se implementaría esto, por ejemplo, en Haskell? Inicialmente leería el registro en un valor de registro (definido por una definición de datos), realizaría diferentes transformaciones aplicando funciones a este valor inicial (cada valor intermedio es una copia nueva y modificada del registro original) y luego escribiría el valor de registro final a la base de datos.
¿Es esto todo lo que hay que hacer? ¿Cómo puedo asegurarme de que en cada momento solo una copia del registro sea válida / accesible? Uno no quiere tener diferentes valores inmutables que representen diferentes instantáneas del mismo objeto para ser accesibles al mismo tiempo.
Respuestas:
La forma habitual de realizar cambios de estado en un lenguaje puro como Haskell es modelarlos como funciones que toman el estado anterior y devuelven una versión modificada. Incluso para objetos complejos, esto es eficiente debido a la estrategia de evaluación perezosa de Haskell: aunque está creando sintácticamente un nuevo objeto, no se copia en su totalidad; cada campo se evalúa solo cuando es necesario.
Si tiene más de unos pocos cambios de estado local, las cosas pueden volverse torpes, que es donde entran las mónadas. El paradigma de la mónada se puede utilizar para encapsular un estado y sus cambios; El ejemplo de libro de texto es la
State
mónada que viene con una instalación estándar de Haskell. Sin embargo, tenga en cuenta que una mónada no es nada especial: es solo un tipo de datos que expone dos métodos (>>=
yreturn
) y cumple con algunas expectativas (las 'leyes de la mónada'). Debajo del capó, la mónada del Estado hace exactamente lo mismo: tomar el estado anterior y devolver un estado modificado; solo la sintaxis es mejor.fuente
No soy un desarrollador de lenguaje funcional, así que por favor derribenme en llamas si me equivoco, pero si es correcto, podría ser una analogía interesante.
Una vez me dijeron que Excel es esencialmente un lenguaje funcional. No estoy hablando de VBA y demás, estoy hablando de lo que sucede en la hoja.
Entonces tiene entradas, que pueden ser tabulares, celdas individuales o rangos con nombre, y así sucesivamente, y a través de una cadena de operaciones termina con un resultado, o muchos resultados. Cambie una entrada e inmediatamente fluirá.
¿Esa analogía retiene el agua?
fuente
Supongo que estás hablando de la característica sin estado del lenguaje funcional puro.
Toma el estado inicial como entrada, devuelve el estado final como salida. Nada fundamentalmente diferente de lo que haces en un idioma con una noción de estado, excepto que eres más explícito al respecto y eso puede ser tedioso y menos eficiente (*).
Tenga en cuenta que no necesariamente tiene que modificar todos los lugares que hacen referencia a su objeto: pueden contener un token y luego solo tiene que modificar la estructura de datos que asigna los tokens a su estado actual. Para entonces, está implementando un sistema completo con un lenguaje sin estado y recupera los problemas de los idiomas completos.
(*) Por ejemplo, he buscado, y no he encontrado, la estructura de datos que me permite devolver en O (1) una copia modificada de una estructura de datos indexable por enteros consecutivos en O (1) también.
fuente
[(Int, v)]
le permitirá reemplazar el valor en cualquier índice en tiempo constante simplemente consiguiendo el nuevo valor. Desventajas: el valor anterior todavía está tomando RAM y la búsqueda es lineal.En resumen, cada estado de una entidad es su propia entidad. Entonces, en su lógica comercial clásica de "ordenar", hay una
Order
entidad y unaOrderVersion
entidad. Ambos son inmutables. La lógica que agrega una línea de pedido toma la versión anterior y una nuevaOrderLineItemVersion
como entrada y devuelve una nuevaOrderVersion
entidad.Facilita algunas cosas (particularmente la funcionalidad "deshacer"), pero algunas cosas son más difíciles.
fuente