2012-03-06 13 views
8

considerar algunos transformadores monad pila, dicenCómo tenedor en el interior del transformador mónada

{-# LANGUAGE GeneralizedNewtypeDeriving #-} 
... 
newtype J = J { runJ :: ErrorT Foo (StateT Bar IO) a } deriving (Applicative, Functor, etc) 

y algunas funciones en J:

peekNextQuux :: J Quux 
peekNextQuux = ... 

withJ :: J a -> IO (Either Foo a) 
withJ = ... 

Entonces me encontré dentro de J contexto. Puedo escribir

f = withJ $ peekNextQuux >>= liftIO . print 

Ahora para esta jornada y quuxes de impresión dentro hilo separado dentro J contexto

g = withJ . liftIO . forkIO . forever $ peekNextQuux >>= liftIO . print 

Lo que obviamente no va a funcionar. Supongo que hay alguna manera de resolver un problema tan simple, simplemente no puedo resolverlo.

Respuesta

8

¿Cómo espera que funcione? El subproceso independiente debe tener acceso a algún estado y a un cierto manejo de errores, porque J envuelve StateT y ErrorT. ¿Cómo debería acceder el hilo a esto? Cuando el estado se actualiza en el nuevo hilo, ¿debería cambiarse en el hilo viejo también? Cuando el nuevo hilo arroja una excepción, ¿debería detenerse el hilo viejo?

No puede funcionar, porque StateT y ErrorT son transformadores de mónada pura, por lo que los comportamientos que describí no son posibles de implementar. Usted debe pasar explícitamente el estado para el nuevo hilo y ejecutar una nueva mónada estado allí para que funcione:

g = withJ . ... $ do 
    state <- get 
    liftIO . forkIO $ do 
    flip execStateT state . forever $ peekNextQuux >>= liftIO . print 
+0

Gracias, eso funcionó. –

9

No estoy seguro de si esto es lo que necesita, pero parece que usted está buscando una función

forkJ :: J() -> J ThreadId 

que es similar a forkIO, pero funciona en contexto J en su lugar. En general, todos los puntos de dflemstr son válidos. Hay muchas preguntas sin resolver sobre la gestión estatal debido a la pureza de Haskell.

Sin embargo, si está dispuesto a reestructurar su lógica un poco, una opción que puede funcionar para usted (si todo lo que está buscando es un hilo separado con acceso al estado original cuando emitió el tenedor) es el pakcage lifted-base, que depende del control de mónada. Básicamente, le dará la función de forkJ anterior siempre que tenga IO en la parte inferior de la pila de transformadores.

Ahora, si desea que los 2 subprocesos se comuniquen con estado, de modo que los errores generados en el hijo se propaguen a la secuencia principal como parte de la maquinaria ErrorT, esto simplemente no es posible (como se explicó dflemstr). Sin embargo, puede establecer un canal de comunicación entre los 2 hilos utilizando una construcción de la familia de módulos de Control.Concurrent. Uno de los siguientes módulos puede tener lo que necesita:

Control.Concurrent.Chan 
Control.Concurrent.MVar 
Control.Concurrent.STM 
+0

Bien, echaré un vistazo a 'levantar-base'. Gracias. –

Cuestiones relacionadas