Considere el siguiente programa de ejemplo:Haskell: casos superpuestos
next :: Int -> Int
next i
| 0 == m2 = d2
| otherwise = 3 * i + 1
where
(d2, m2) = i `divMod` 2
loopIteration :: MaybeT (StateT Int IO)()
loopIteration = do
i <- get
guard $ i > 1
liftIO $ print i
modify next
main :: IO()
main = do
(`runStateT` 31) . runMaybeT . forever $ loopIteration
return()
Sólo puede utilizar get
en lugar de lift get
porque instance MonadState s m => MonadState s (MaybeT m)
se define en el módulo de MaybeT.
Muchas de estas instancias se definen en una especie de explosión combinatoria.
Hubiera sido agradable (aunque imposible por qué??) Si tuviéramos el siguiente tipo de clase:
{-# LANGUAGE MultiParamTypeClasses #-}
class SuperMonad m s where
lifts :: m a -> s a
Vamos a tratar de definirlo como tal:
{-# LANGUAGE FlexibleInstances, ... #-}
instance SuperMonad a a where
lifts = id
instance (SuperMonad a b, MonadTrans t, Monad b) => SuperMonad a (t b) where
lifts = lift . lifts
Usando lifts $ print i
vez de liftIO $ print i
funciona, lo cual es bueno.
Pero usar lifts (get :: StateT Int IO Int)
en lugar de (get :: MaybeT (StateT Int IO) Int)
no funciona.
GHC (6.10.3) da el siguiente error:
Overlapping instances for SuperMonad
(StateT Int IO) (StateT Int IO)
arising from a use of `lifts'
Matching instances:
instance SuperMonad a a
instance (SuperMonad a b, MonadTrans t, Monad b) =>
SuperMonad a (t b)
In a stmt of a 'do' expression:
i <- lifts (get :: StateT Int IO Int)
puedo ver por qué "instance SuperMonad a a
" se aplica. Pero, ¿por qué GHC piensa que el otro también lo hace?
+1 para una excelente redacción. –
gracias! siguiendo su entrada, ¡he logrado hacerlo! – yairchu
Las superposiciones están muy lejos en mi lista de extensiones (incluso más allá de las IndecidiblesInstancias, lo que simplemente hace que el trabajo del compilador sea mucho más difícil), no solo no es portátil, sino que también rompe las garantías de seguridad que normalmente proporciona Haskell. Aconsejaría a OP que lo succionara y tratara de 'levantar' o no 'levantar' manualmente, en lugar de agregar este truco ... pero esa es mi opinión. – ephemient