Quindi, in transformers
vedo,Perché MonadIO è specifico per IO, piuttosto che un MonadTrans più generico?
class (Monad m) => MonadIO m where
-- | Lift a computation from the 'IO' monad.
liftIO :: IO a -> m a
instance MonadIO IO where
liftIO = id
e capisco che la ragione per cui questo differisce da MonadTrans è che se avete un po M1T (M2T (M3T (M4T IO))) x
fatta di 4 trasformatori monade composti, allora non si vuole, ma si lift . lift . lift . lift $ putStrLn "abc"
Piuttosto solo liftIO $ putStrLn "abc"
.
Ma questa specificità per IO
sembra molto strana quando la definizione fondamentale di cui sopra sembra essere questa strana serie di ricorsioni con liftIO
. Sembra che ci dovrebbe essere o una dichiarazione newtype per qualche combinatore come (ExceptT :~: MaybeT) IO x
in modo che un singolo lift
è tutto ciò che mai bisogno (Suppongo che questo è un trasformatore trasformatore di monade?), Oppure un po 'più param tipo di classe,
class (Monad m) => MonadEmbed e m
-- | Lift a computation from the `e` monad.
embed :: e a -> m a
instance (Monad m) => MonadEmbed m m where
embed = id
Perché lo transformers
non utilizza uno di questi approcci in modo che le sequenze MonadTrans non debbano essere radicate in IO
? È solo il fatto che i trasformatori gestiscono tutti gli "altri" effetti in modo che le uniche cose in fondo siano o Identity
(già gestite con return :: a -> m a
) o IO
? O quanto sopra richiede qualcosa come UndecidableInstances che la libreria transformers
non può contenere? O cosa?
AFAIK 'transformers' è Haskell 98 che ** include ** include classi di tipo multiparametro, quindi l'esempio" non è consentito "in base a questa restrizione. La libreria 'mtl' fornisce alcuni tipi di caratteri come' MonadState' e alcune istanze che consentono di evitare di sollevare molte volte. – Bakuriu