2010-10-13 17 views
64

¿En qué situaciones se debe usar liftIO? Cuando estoy usando ErrorT String IO, la función lift funciona para levantar acciones IO en ErrorT, por lo que liftIO parece superfluo.Haskell: ascensor vs liftIO

Respuesta

75

lift siempre se levanta de la capa "anterior". Si necesita levantar desde la segunda capa, necesitará lift . lift y así sucesivamente.

Por otro lado, liftIO siempre se levanta de la capa IO (que, cuando está presente, siempre está en la parte inferior de la pila). Por lo tanto, si tiene más de 2 capas de mónadas, apreciará liftIO.

comparar el tipo del argumento en los siguientes lambdas:.

type T = ReaderT Int (WriterT String IO) Bool 

> :t \x -> (lift x :: T) 
\x -> (lift x :: T) :: WriterT String IO Bool -> T 

> :t \x -> (liftIO x :: T) 
\x -> (liftIO x :: T) :: IO Bool -> T 
+26

Generalmente usaré 'liftIO' para levantar a la capa IO incluso si' lift' es suficiente, porque entonces puedo cambiar la pila de mónadas y el código aún funciona. –

+11

@John: buen punto. Y también hace obvio que estás levantando IO y no cualquier otra mónada. –

28

liftIO es sólo un acceso directo a la mónada IO, lo que la mónada que están en el fondo, liftIO es igual a la utilización de un número variable de ascensores . Al principio, esto puede parecer redundante, pero usar liftIO tiene una gran ventaja: hace que tu código IO sea independiente de la construcción de Monad real para que puedas reutilizar el mismo código sin importar la cantidad de capa de tu Monad final (esto es bastante importante) al escribir un transformador de mónada).

En la otra mano, liftIO no está disponible de forma gratuita, como lo hace el ascensor: los transformadores Monad que está utilizando deben tener soporte, por ejemplo. la Mónada en la que te encuentras debe ser una instancia de la clase MonadIO, pero la mayoría de las Mónadas actuales (y, por supuesto, el verificador de tipos comprobará esto en el momento de la compilación: ¡esa es la fuerza de Haskell!).