¿En qué situaciones se debe liftIO
utilizar? Cuando estoy usando ErrorT String IO
, la lift
función funciona para elevar las acciones de IO ErrorT
, por lo que liftIO
parece superflua.
haskell
monad-transformers
Lachlan
fuente
fuente
liftIO
para subir a la capa IO incluso silift
es suficiente, porque entonces puedo cambiar la pila de mónadas y el código aún funciona.lift
en esta respuesta (y la pregunta) se supone que es deControl.Monad.Trans.Class
, ¿supongo? ¿No es elMonadic lifting
o el levantamiento general como se describe en la primera sección aquí ?liftIO es solo un acceso directo a IO Monad, cualquiera que sea la Monad en la que se encuentre. Básicamente, liftIO equivale a usar un número variable de ascensores. Al principio, esto puede parecer redundante, pero usar liftIO tiene una gran ventaja: hace que su código IO sea independiente de la construcción real de Monad, por lo que puede reutilizar el mismo código sin importar la cantidad de capa de la que se haya construido su Monad final (esto es bastante importante al escribir un transformador de mónada).
Por otro lado, liftIO no viene gratis, como lo hace lift: los transformadores Monad que está utilizando deben tener soporte para él, por ejemplo, el Monad en el que se encuentra debe ser una instancia de la clase MonadIO, pero la mayoría de las Monad hoy en día lo hacen. (y, por supuesto, el verificador de tipos comprobará esto por usted en el momento de la compilación: ¡esa es la fortaleza de Haskell!).
fuente
Todas las respuestas anteriores explican bastante bien la diferencia. Solo quería arrojar algo de luz sobre el funcionamiento interno para que sea más fácil entender cómo
liftIO
no es algo mágico (para los Haskellers novatos como yo).liftIO :: IO a -> m a
es una herramienta inteligente basada en
lift :: (Control.Monad.Trans.Class.MonadTrans t, Monad m) => m a -> t m a
y se utiliza con mayor frecuencia cuando la mónada inferior es
IO
. Para laIO
mónada, su definición es bastante simple.class (Monad m) => MonadIO m where liftIO :: IO a -> m a instance MonadIO IO where liftIO = id
Así de simple ...
liftIO
es de hecho soloid
para laIO
mónada y básicamenteIO
es el único que entra dentro de la definición de la clase de tipo.El caso es que, cuando tenemos un tipo de mónada que se compone de varias capas de transformadores de mónada
IO
, es mejor tener unaMonadIO
instancia para cada una de esas capas de transformador de mónada. Por ejemplo, laMonadIO
instancia de tambiénMaybeT m
requierem
ser deMonadIO
typeclass.Escribir una
MonadIO
instancia también es básicamente una tarea muy simple. PorqueMaybeT m
se define comoinstance (MonadIO m) => MonadIO (MaybeT m) where liftIO = lift . liftIO
o por
StateT s m
instance (MonadIO m) => MonadIO (StateT s m) where liftIO = lift . liftIO
Son todos iguales. Imagínese cuando tiene una pila de transformadores de 4 capas, entonces necesita hacerlo
lift . lift . lift . lift $ myIOAction
o simplementeliftIO myIOAction
. Si lo piensa, cada unolift . liftIO
lo llevará una capa hacia abajo en la pila hasta que cava hastaIO
dondeliftIO
se define comoid
y finaliza con el mismo código que el compuestolift
anterior.Básicamente, esta es la razón por la que, independientemente de la configuración de la pila de transformadores, siempre que todas las capas subyacentes sean miembros de
MonadIO
yMonadTrans
una solaliftIO
esté bien.fuente