Programación funcional: estado vs. reasignación

votos
13

Necesito ayuda para entender la diferencia entre mi noción de estado de POO actual y la forma en que se haría en un lenguaje funcional como Haskell o Clojure.

Para utilizar un ejemplo manido, digamos que estamos tratando con objetos / estructuras simplificados de la cuenta bancaria / lo que sea. En un lenguaje OOP, tendría alguna clase con una referencia a una cuenta bancaria, que tendría variables de instancia para cosas como la tasa de interés, y métodos como setInterestRate () que cambian el estado del objeto y generalmente no devuelven nada. En decir, Clojure, tendría una estructura de cuenta bancaria (un hashmap glorificado) y funciones especiales que toman un parámetro de cuenta bancaria y otra información, y devuelve una nueva estructura. Entonces, en lugar de cambiar el estado del objeto original, ahora tengo uno nuevo con las modificaciones deseadas.

Entonces ... ¿qué hago con eso? ¿Sobrescribir cualquier variable que esté haciendo referencia a la cuenta bancaria anterior? Si es así, ¿tiene eso ventajas sobre el enfoque OOP que cambia el estado? Al final, en ambos casos parece que uno tiene una variable que hace referencia al objeto con los cambios necesarios. Retardado como soy, solo tengo un concepto vago de lo que está sucediendo.

Espero que tenga sentido, gracias por cualquier ayuda!

Publicado el 09/12/2008 a las 20:24
fuente por usuario
En otros idiomas...                            


4 respuestas

votos
11

En un estilo funcional puro, nunca sobrescribirá ninguna variable.

Una analogía sería con el espacio-tiempo en física. Si considera el mundo como 3d, entonces los objetos no tienen posiciones fijas, se mueven con el tiempo. Para aplicar las matemáticas al mundo físico, por lo tanto, agregamos una dimensión de tiempo y consideramos los valores de varias propiedades en momentos específicos. Al hacerlo, hemos convertido los objetos de nuestro estudio en constantes. De manera similar, en la programación, se tiene una simplicidad conceptual al trabajar con valores inmutables. Los objetos con una identidad en el mundo real se pueden modelar como una secuencia de valores inmutables (los estados del objeto en tiempos crecientes) en lugar de como un único valor que cambia.

Por supuesto, los detalles de cómo asociar la secuencia de valores a una "identidad de objeto" pueden ser un poco peludos. Haskell tiene mónadas que te permiten modelar el estado. La Programación Reactiva Funcional es un intento más literal de modelar objetos en el mundo con actualizaciones funcionales puras, que creo que es una dirección muy prometedora para la programación.

Notaré que Clojure, a diferencia de Haskell, no es puro, y puede actualizar las variables como sugirió. Si solo está actualizando algunas variables en un nivel alto, probablemente aún disfrutará de muchos de los beneficios de simplicidad conceptual de la programación funcional.

Respondida el 09/12/2008 a las 21:10
fuente por usuario

votos
8

Presumiblemente en el mundo OO tiene un bucle y está modificando estas cuentas bancarias una y otra vez en respuesta a las solicitudes. Supongamos que tiene toda una cartera de cuentas y éstas tienen el tipo Portafolio. Entonces en Haskell escribirías una función pura

updatePortfolio :: Request -> Portfolio -> Portfolio

Y su bucle principal puede leer las solicitudes de entrada estándar y mantener su cartera actualizada. (El ejemplo no es muy útil a menos que también pueda escribir la cartera, pero es más simple).

readRequest :: IO Request  -- an action that, when performed, reads a Request with side effects

main :: Portfolio -> IO ()  -- a completely useless program that updates a Portfolio in response to a stream of Requests

main portfolio = do req <- readRequest
                    main (updatePortfolio req)

y ahora espero que vea lo que sucedió con su estado mutable: en un programa funcional típico, establezca que los cambios se pasan como un parámetro a una función. Cuando el estado cambia, realiza una nueva llamada de función. La llamada está en posición de cola (puede buscar 'tail call' adecuada) y por lo tanto no usa ningún recurso adicional, y de hecho cuando el compilador genera código ensamblado genera un bucle, y mantendrá el puntero al cartera en constante cambio en un registro.

Este es un ejemplo muy juguetón pero espero que te dé un poco del sabor de un lenguaje funcional.

Respondida el 10/12/2008 a las 04:57
fuente por usuario

votos
4

Entonces ... ¿qué hago con eso? ¿Sobrescribir cualquier variable que esté haciendo referencia a la cuenta bancaria anterior?

Si es así, ¿tiene eso ventajas sobre el enfoque OOP que cambia el estado?

Digamos que el cálculo de cualquier acción que hagas en esa estructura lleva mucho tiempo y algo pasa a mitad de camino y necesitas volver a la estructura original o el cálculo generó un error. Con la interpretación que me ha presentado de OO (utilizando una referencia, porque puede tener un lenguaje de OO inmutable) los datos podrían estar corruptos: es desconocido a menos que se haya proporcionado suficiente información de la llamada a función fallida, y sugiero que falló mal. En un enfoque funcional, usted está seguro de que su estructura de datos original es correcta, porque inicialmente hizo una copia.

Amplíe este escenario en aplicaciones de subprocesos múltiples. Podemos asegurarnos de que nadie más esté usando la estructura de datos que somos, ya que todos tenemos nuestra propia versión de la misma.

Además, podemos ahorrar espacio al usar datos de la otra estructura de la que estamos copiando. Un ejemplo clásico es cuando se agrega un elemento al encabezado de una lista. Si tenemos un puntero al segundo elemento y un puntero al primer elemento, podemos hacer referencia a ambas listas con solo el tamaño del primero (ver a continuación). Sin inmutabilidad, no podemos garantizar esto.

        b__
           |  
a -> [6|] -+-> [5|] -> [4|] -> [3|] -> [2|] -> [1|x]
Respondida el 09/12/2008 a las 20:58
fuente por usuario

votos
1

Mire Haskell, que es un lenguaje funcional puro, no tiene reasignación alguna, ni ningún otro efecto secundario: para hacer IO, en la construcción de la mónada IO realmente reemplaza el RealWorld con una nueva instancia del mundo que tiene, por ejemplo, nuevo texto mostrado en la consola.

Respondida el 09/12/2008 a las 22:29
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more