Pregunta

hecho una pregunta sobre la programación funcional, y recibí (bueno!) respuestas que dieron lugar a más preguntas (como parece ser el caso con el aprendizaje, a veces). Aquí hay un par de ejemplos:

  1. Una de las respuestas hecho referencia a una ventaja de estructuras de datos inmutables: cada hilo puede tener su propia copia. Ahora, para mí, esto suena más bien como un sistema de control de versiones (para usar una analogía), donde en vez de código que alguien ha comprobado de manera que no puede ser modificado por cualquier otra persona de bloqueo, todo el mundo puede comprobar fuera de sus propias copias. Suena bien. Sin embargo, en VCS tiene el concepto de "fusión" cambios, en el caso de que dos personas cambiaron la misma materia. Parece que este problema sin duda podría llegar en un escenario de multiproceso ... así que ¿cómo se "fusionando" terminado cuando es importante que los hilos ver los datos más recientes?

  2. Esta respuesta habló sobre el caso en el que estaban siendo operaciones lleva a cabo en un bucle en un objeto, y cómo se puede utilizar un nuevo objeto cada vez a través en lugar de actualizar una vieja. Sin embargo, digamos que el bankAccount está siendo actualizada en un escenario de no-loop - por ejemplo, un sistema bancario interfaz gráfica de usuario. El operador hace clic en el botón "Cambiar la Tasa de Interés", que dispara un evento que lo haría (en C #, por ejemplo) hacer algo como bankAccount.InterestRate = newRateFromUser. Siento que estoy siendo densa aquí, pero espero que mi ejemplo tiene sentido: tiene que haber alguna manera de que el objeto se actualiza, ¿verdad? Varias otras cosas pueden depender de los nuevos datos.

De todos modos, si usted puede ayudar a conseguir mi cabeza alrededor del cambio de paradigma, estaría agradecido. Recuerdo mi cerebro pasando por fases "estúpidos" similares al aprender programación orientada a objetos después de un fondo de enfoque simple imperativo de procedimiento para la codificación.

¿Fue útil?

Solución

Respuesta a la parte 1: Los objetos inmutables por si mismas no apoyar nada por el estilo "fusión" para permitir que los resultados de dos actualizaciones de hilo que se combinan. Hay dos estrategias principales para ello: el pesimista y el optimista. Si usted es pesimista, se asume que es muy probable que los dos hilos se desee actualizar la misma pieza de datos al mismo tiempo. Así que usted emplea bloqueo, de tal manera que el segundo hilo se congelará hasta el primer hilo dice que ha terminado. Si usted es optimista de que esto ocurrirá sólo en raras ocasiones, deja que los dos hilos trabajan en su propia copia lógica de los datos. El que termine primero suministra la nueva versión, y el otro tiene que empezar de nuevo desde el principio - sólo que ahora comienza a partir de los resultados de los cambios de la primera rosca. Este reinicio caro sólo ocurre de vez en cuando, sin embargo, lo que más del todo lo que tiene un mejor rendimiento debido a la falta de bloqueo (aunque esto sólo es cierto si su optimismo estaba bien colocado sobre cómo rara vez ocurre un choque).

Parte 2: lenguas sin Estado funcionales puros realmente no eliminan ese problema. Incluso un programa Haskell pura puede tener estado asociado con él. La diferencia es que el código de estado tiene un tipo de retorno diferente. Una función que manipula estado se expresa como una secuencia de operaciones que operan sobre un objeto que representa ese estado. En un ejemplo absurdo, considerar el sistema de archivos del equipo. Cada vez que un programa modifica el contenido de un archivo (incluso por un solo byte) se ha creado una nueva "versión" de todo el sistema de archivos. Y, por extensión, una nueva versión de todo el universo. Pero vamos a centrarnos en el sistema de archivos por ahora. Cualquier otra parte del programa que examina el sistema de archivos puede ahora verse afectada por ese byte modificado. Así Haskell dice que las funciones que operan en el sistema de archivos deben pasar de manera efectiva alrededor de un objeto que representa una versión del sistema de archivos. Entonces, porque esto sería tedioso para la manipulación manual de un rato, la exigencia de adentro hacia afuera y dice que si una función quiere ser capaz de hacer IO, que debe devolver un tipo de objeto contenedor. En el interior del recipiente es el valor de la función quiere volver. Sin embargo, el contenedor sirve como evidencia de que la función sea también tiene efectos secundarios ni puede ver los efectos secundarios. Esto significa que el sistema de tipos de Haskell es capaz de distinguir entre las funciones-con-los efectos secundarios y las funciones de "puros". Por lo que ayuda a contener y administrar el statefulness de código, sin llegar a su eliminación.

Otros consejos

Piense en la clase String en .Net (que es un objeto inmutable). Si se llama a un método en una cadena, se obtiene una nueva copia:

String s1 = "there";
String s2 = s1.Insert(0, "hello ");

Console.Writeline("string 1: " + s1);
Console.Writeline("string 2: " + s2);

Esta es la salida:

string 1: no

string 2: ¡Hola

Comparar este comportamiento a StringBuilder, que tiene básicamente el mismo método de firma:

StringBuilder sb  = new StringBuilder("there");
StringBuilder sb2 = sb.Insert(0, "hi ");

Console.WriteLine("sb 1: " + sb.ToString());
Console.WriteLine("sb 2: " + sb2.ToString());

Debido StringBuilder es mutable, ambas variables apuntan al mismo objeto. La salida será:

sb 1: Hola

sb 2: Hola

Así que, a pesar de todo no se puede cambiar una cadena una vez que se haya creado. s1 siempre será "no" hasta el fin del tiempo (o hasta que el recolector de basura). Eso es importante, porque en el roscado puede paso siempre a través de cada personaje e imprimir su valor sabiendo que siempre va a imprimir 'ahí'. Si ha iniciado la impresión de la StringBuilder después de su creación, es posible imprimir los dos primeros caracteres de allí y get'th'. Ahora, imaginemos otro hilo viene anuncios insertos 'hola'. El valor es ahora diferente! Al imprimir el tercer carácter, que es el espacio de 'hola'. Así se imprime:. 'Th hay'

En cuanto a la # 2 ...

  

Muchas otras cosas pueden depender de la   los nuevos datos.

Esto es lo que los puristas llaman un "efecto". La noción de múltiples referencias a objetos con el mismo objeto mutable es la esencia del estado mutable y el quid de la cuestión. POO en, puede tener un objeto "a" de tipo CuentaBancaria, y si usted lee a.Balance o lo que sea diferente al veces es posible que vea valores diferentes. Por el contrario, en el más puro FP, si "A" tiene el tipo CuentaBancaria, entonces es inmutable y tiene el mismo valor independientemente del tiempo.

Sin embargo, dado un CuentaBancaria es presumiblemente un objeto que queremos modelar cuyo estado varía con el tiempo, que habría de FP codificar esa información en el tipo. Por lo tanto "a" podrían tener tipo "IO CuentaBancaria", o algún otro tipo monádico, que esencialmente se reduce a hacer "un" ser en realidad una función que toma como entrada "el estado previo del mundo" (o estado previo de las tasas de interés de los bancos , o lo que sea), y devuelve un nuevo estado del mundo. Actualización de la tasa de interés sería otra operación con un tipo que representa el efecto (por ejemplo, otra operación IO), y por lo tanto se obtendrá una nueva 'mundo', y todo lo que puede depender de la tasa de interés (Estado mundial) sería de datos con una tipo que sabe que tiene que tomar ese mundo como entrada.

Como resultado, la única manera posible llamar "a.Balance" o lo que sea es el uso de código que, gracias a los tipos estáticos, hace cumplir que algunos 'la historia del mundo que nos metió hasta ahora' ha sido sondeado correctamente a el punto de la llamada, y cualquiera que sea la historia del mundo es la entrada afecta a qué resultado nos pondremos de a.Balance.

Leyendo sobre el Estado Mónada puede ser útil para tener una idea de cómo modelar 'compartida estado mutable' puramente.

  1. estructuras de datos inmutables no son como VCS. Pensar en una estructura de datos inmutables como un archivo de sólo lectura. Si su sólo lectura, no importa que está leyendo, que parte del archivo en un momento dado, todo el mundo va a leer la información correcta.

  2. Esa respuesta está hablando de http://en.wikipedia.org/ wiki / Monad_ (functional_programming)

MVCC ( multiversión control de concurrencia )

La solución para el problema que se está refiriendo es descrito por Rich Hickey en su de vídeo presentaciones .

En resumen : en lugar de pasar los datos por referencia directamente a los clientes, se agrega un nivel más en indirección y pasar la referencia a la referencia a los datos. ( Bueno, en realidad le gustaría tener al menos un nivel más de indirección. Pero vamos a suponer que la estructura de datos es muy simple, como la "matriz". )
Dado que los datos es inmutable, cada vez que los datos deben ser cambiados, se crea la copia de la parte modificada ( en el caso de la matriz se debe crear otra matriz! ), más que crear otra referencia a toda la datos "cambiado".
Así que para todos los clientes que utilizan la primera versión de la matriz, que utilizan la referencia a la primera versión. Cada cliente intenta acceder a la segunda versión utiliza la segunda referencia.
La estructura de datos "matriz" no es muy interesante para este método, porque no se puede dividir los datos y que se ven obligados a copiar todo. Sin embargo, para las estructuras de datos más sofisticados, como los árboles, algunas partes de la estructura de datos pueden ser "compartidos", por lo que no se ve obligado a copiar todo cada vez.

Para más detalles, echar un vistazo a este artículo: " Estructuras de datos puramente funcional " por Chris Okasaki.

"inmutable" significa exactamente eso:. No cambia

La forma de los programas funcionales hacen cambios es pasando alrededor de cosas nuevas. Un valor existente no cambia nunca: sólo tiene que construir un nuevo valor y que en vez de pasar. Muy a menudo el nuevo estado de acciones de valor con el viejo; buenos ejemplos de la técnica son listas compuestas de células contras, y la cremallera .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top