voy a responder a su segunda pregunta. En realidad, hay muchas maneras de manejar el estado mutable en Haskell (y otros lenguajes FP). En primer lugar, Haskell soporta el estado mutable en IO, mediante construcciones IORef
y mvar
. Usar estos se sentirá muy familiar para los programadores de idiomas imperativos. También hay versiones especializadas como STRef
y TMVar
, así como matrices mutables, punteros y otros datos variables. El mayor inconveniente es que generalmente solo están disponibles dentro de IO o en una mónada más especializada.
La forma más común de simular el estado en un lenguaje funcional es explícitamente pasar el estado como un argumento de función y el valor devuelto. Por ejemplo:
randomGen :: Seed -> (Int, Seed)
Aquí randomGen
toma un parámetro de semillas y devuelve una nueva semilla. Cada vez que lo llamas, necesitas hacer un seguimiento de la semilla para la próxima iteración. Esta técnica está siempre disponible para aprobar el estado, pero rápidamente se vuelve tediosa.
Probablemente el método más común de Haskell es utilizar una mónada para encapsular este estado. Podemos reemplazar randomGen
con esto:
-- a Random monad is simply a Seed value as state
type Random a = State Seed a
randomGen2 :: Random Int
randomGen2 = do
seed <- get
let (x,seed') = randomGen seed
put seed'
return x
Ahora las funciones que necesitan un PRNG se puede ejecutar dentro de la mónada aleatoria para solicitar cuando sea necesario. Solo necesita proporcionar un estado inicial y el cálculo.
runRandomComputation :: Random a -> Seed -> a
runRandomComputation = evalState
(tenga en cuenta que hay funciones que acortan considerablemente la definición de randomGen2; elegí la versión más explícita).
Si su cálculo aleatorio también necesita acceso a IO
, entonces utiliza la versión del transformador de mónada State, StateT
.
De nota especial es la mónada ST
, que esencialmente proporciona un mecanismo para encapsular las mutaciones IO-específicas lejos del resto de IO. La mónada ST proporciona STRefs, que son una referencia mutable a datos, y también matrices mutables.El uso de ST, es posible definir cosas como esta:
randomList :: Seed -> [Int]
donde [Int] es una lista infinita de números aleatorios (que va de ciclo con el tiempo dependiendo de su PSRG) a partir de la semilla de partida que le des.
Finalmente, está Functional Reactive Programming. Probablemente las bibliotecas actuales más destacadas para esto sean Yampa y Reactive, pero las otras también valen la pena mirar. Hay varias aproximaciones al estado mutable dentro de las diversas implementaciones de FRP; por mi ligero uso de ellos, a menudo parecen similares en concepto a un marco de señalización como en QT o Gtk + (por ejemplo, agregar oyentes para eventos).
Ahora, para la primera pregunta. Para mí, la mayor ventaja es que el estado mutable está separado de otro código en el nivel de tipo. Esto significa que el código no puede modificar accidentalmente el estado a menos que se mencione explícitamente en la firma de tipo. También ofrece un muy buen control del estado de solo lectura frente al estado mutable (Mónada Reader vs. Mónada State). Encuentro muy útil estructurar mi código de esta manera, y es útil poder decir simplemente desde la firma de tipo si una función podría estar mutando inesperadamente.
Personalmente, realmente no tengo ninguna reserva sobre el uso del estado mutable en Haskell. La mayor dificultad es que puede ser tedioso agregar estado a algo que no lo necesitaba anteriormente, pero lo mismo sería tedioso en otros idiomas que he usado para tareas similares (C#, Python).
http://www.haskell.org/all_about_monads/html/statemonad.html –
El manejo del estado en un lenguaje funcional implica pasar el estado a las funciones. Las mónadas simplifican esto. – tylermac
@tylermac nunca pude entender las mónadas, bueno, no puedo decir que soy estúpido, al menos soy BS en CS, pero las mónadas ... ¿conoces buenos tutoriales? – Andrey