2009-12-19 23 views
56

Una cosa que siempre me ha confundido es si es o no un buen momento para usar un IORef. ¿Hay alguna guía que se debe seguir al decidir si usar o no un IORef para una tarea? ¿Cuándo es un buen momento para usar la mónada estatal sobre un IORef?¿Cuándo está bien usar un IORef?

+0

http://stackoverflow.com/questions/10298664/avoiding-iorefs-in-pure-code –

Respuesta

69

El estado y su ST relativa producen cálculos estadísticos "monolíticos" que se pueden ejecutar como unidades. Básicamente tratan el estado mutable como datos intermedios, que se necesitan para producir un resultado, pero no deberían, en sí mismos, ser de interés para el resto del programa.

Por otro lado, lo que uno coloca dentro de un IORef no es un 'cálculo' para ejecutar; es simplemente un cuadro que contiene un valor simple que puede usarse dentro de IO de maneras bastante arbitrarias. Este recuadro puede colocarse dentro de las estructuras de datos, pasar alrededor de la porción (IO) del programa, reemplazar sus contenidos cuando sea conveniente, ser cerrado por una función, etc. De hecho, es bastante desordenado la naturaleza de las variables y los punteros de lenguajes como C podrían modelarse con IORefs, proporcionando gran asistencia a cualquier programador C experto que desee mantener su reputación de poder escribir código C en cualquier idioma ... Esto es algo que definitivamente debe usarse con cuidado.

Sin embargo, es a veces muy difícil de manejar, por no decir imposible, para aislar todas las interacciones con un pedazo de estado mutable en un solo bloque de código - algunas piezas de Estado simplemente debe pasar alrededor, poner dentro de estructuras de datos, etc. En tales casos, el enfoque de caja puede ser la única opción. El chapter introducing mutable state del tutorial Write Yourself a Scheme in 48 Hours (altamente recomendado, por cierto) proporciona un ejemplo. (Consulte el enlace para ver una buena discusión sobre por qué es realmente más apropiado usar IORefs, en lugar de State o ST, para modelar entornos Scheme en un determinado diseño de un intérprete Scheme.)

En resumen, esos entornos necesitan para anidar de forma arbitraria, mantenida entre instancias de interacción del usuario (un (define x 1) escrito en el esquema REPL probablemente resulte en que el usuario pueda escribir más tarde en x y recuperar 1 como el valor), ponga dentro objetos modelando funciones de esquema (ya que Scheme funciona cerca de los entornos en los que se crean) etc.

En resumen, diría que si una tarea parece adecuada para ella, State tenderá a proporcionar la solución más limpia. Si se necesitan múltiples piezas de estado por separado, quizás ST puede ayudar. Sin embargo, si el cálculo con estado es difícil de manejar o imposible de bloquear en su propia pieza de código, el estado debe persistir en una forma modificable durante gran parte de la vida de un programa complejo, etc., entonces IORefs puede ser solo el lo apropiado

Por otra parte, si uno necesita el tipo de estado mutable que puede transmitirse e interactuar de forma controlada por el código IO, ¿por qué no echa un vistazo a STM y sus TVars! Son mucho más agradables en presencia de concurrencia, tanto, de hecho, como para hacer que la resolución de algunas tareas relacionadas con la concurrencia sea realmente simple. Sin embargo, esto no está realmente relacionado con la pregunta, así que me resistiré a insistir en la elaboración.:-)

+0

Publicación muy informativa. Gracias por tomarse el tiempo de escribir esto para mí. <3 – Rayne

+0

Además, no tome personalmente a los no votantes. La gente vota a Dons solo porque él es dons. : p – Rayne

+0

Me alegro de que le haya gustado, gracias por informarme. Es mi primera pieza (algo) más larga en Haskell y fue muy divertido escribirla. :-) –

1

Uso STRef cuando el estado está localizado y no requiere interacción con el entorno.

12

Hmm. Utilizaría un IORef cuando necesite algún estado mutable, pero se encuentre en un entorno con un solo subproceso. O cuando desea un campo mutable dentro de una estructura más grande que a su vez está en manos de una variable de sincronización.

En general, use MVars. Tienen una semántica más robusta.

3

En lo personal, yo diría que es muy bien utilizar IORef s cuando y sólo cuando ya está usando IO. De lo contrario, siempre State, a menos que necesite el rendimiento superior de ST. Es posible utilizar múltiples hilos de estado con la mónada State, con algunas funciones auxiliares: simplemente convierte el estado en una tupla o registro, y define funciones para establecer, obtener o actualizar cada campo por separado.

En particular, no suele haber mucho sentido en el uso de StateT s IO. Si ya está en IO, ya tiene un estado mutable, por lo que también podría usarlo - ReaderT (IORef s) IO por ejemplo.

+0

Eso me abrió un poco los ojos. Para un principiante, 'StateT s IO' era una solución obvia, y * obviamente inferior * ahora. –

+0

¿No hay una diferencia entre 'State' y' ST' que en 'ST' el estado se modifica 'in-place'? – Alexey

+0

@Alexey: Sí, 'State' y' ST' son diferentes, pero ambos son capaces de resolver esencialmente los mismos problemas. –

Cuestiones relacionadas