Pregunta

A menudo me encuentro con este patrón en Haskell código:

options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar

...

doSomething :: Foo -> Bar
doSomething = unsafePerformIO $ do
  opt <- readMVar options
  doSomething' where ...

Básicamente, se tiene un registro de opciones o algo similar, que se fija inicialmente en el programa del principio.Como el programador es perezoso, él no quiere llevar a la options grabar todo el programa.Él define a un MVar para mantener definido por un feo uso de unsafePerformIO.El programador asegura, que el estado es sólo una vez y antes de cualquier operación ha tenido lugar.Ahora cada parte del programa a utilizar unsafePerformIO de nuevo, sólo para extraer las opciones.

En mi opinión, este tipo de variable se considera pragmatismo puro (no me pegaba).Hay una biblioteca que resume este concepto de distancia y se asegura de que la variable se establece sólo una vez, es decir,que no haya ninguna llamada se realiza antes de que la inicialización y que uno no tiene que escribir unsafeFireZeMissilesAndMakeYourCodeUglyAnd DisgustingBecauseOfThisLongFunctionName

¿Fue útil?

Solución

Si está utilizando MVar para mantener configuraciones o algo similar, ¿por qué no prueba el lector mónada?

foo :: ReaderT OptionRecord IO ()
foo = do
    options <- ask
    fireMissiles

main = runReaderT foo (OptionRecord "foo")

(Y lector normal si no necesita IO: P)

Otros consejos

Aquellos que intercambiarían transparencia referencial esencial por un poco de conveniencia temporal no merecen pureza ni conveniencia.

Esta es una mala idea.El código en el que estás encontrando esto es un código incorrecto.*

No hay manera de concluir completamente este patrón de forma segura, porque no es un patrón seguro.No hagas esto en tu código.No busque una forma segura de hacer esto.No existe una forma segura de hacer esto.Pon el unsafePerformIO Tírese al suelo, lentamente, y aléjese de la consola...

*Hay razones legítimas por las que la gente usa MVars de nivel superior, pero esas razones tienen que ver con enlaces a código externo en su mayor parte, o algunas otras cosas en las que la alternativa es muy complicada.En esos casos, hasta donde yo sé, sin embargo, los MVars de nivel superior son no se accede por detrás unsafePerformIO.

El uso de parámetros implícitos.Son un poco menos pesado que el de hacer cada función tiene Reader o ReaderT en su tipo.Tienes que cambiar el tipo de las firmas de sus funciones, pero creo que ese cambio puede ser escrito.(Sería una buena característica de un Haskell IDE).

Hay una razón importante para no utilizar este patrón.Hasta donde yo sé, en

options :: MVar OptionRecord
options = unsafePerformIO $ newEmptyMVar

Haskell no ofrece garantías de que options Se evaluará una sola vez.Dado que el resultado de option es un valor puro, se puede memorizar y reutilizar, pero también se puede volver a calcular para cada llamada (es decir,en línea) y el significado del programa no debe cambiar (al contrario de su caso).

Si aún decides usar este patrón, asegúrese de agregar {-# NOINLINE options #-}, de lo contrario, podría insertarse y su programa fallará.(Y con esto nos salimos de las garantías dadas por el lenguaje y el sistema de tipos y confiamos únicamente en la implementación de un compilador en particular).

Este tema ha sido ampliamente discutido y las posibles soluciones están muy bien resumidas en Haskell Wiki en Estado mutable de nivel superior.Actualmente no es posible abstraer este patrón de forma segura sin algún soporte adicional del compilador.

A menudo encuentro este patrón en el código Haskell:

Leer código diferente.

Como el programador es vago, no quiere llevar el registro de opciones por todo el programa.Define un MVar para conservarlo, definido por un uso feo de unsafePerformIO.El programador se asegura de que el estado se establezca sólo una vez y antes de que se haya realizado cualquier operación.Ahora cada parte del programa tiene que usar unsafePerformIO nuevamente, solo para extraer las opciones.

Suena literalmente exactamente lo que logra la mónada lectora, excepto que la mónada lectora lo hace de forma segura.En lugar de adaptarse a su propia pereza, simplemente escriba un buen código.

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