Odpowiedź bheklilra dała mi przykład, w którym transformator monady wytwarza coś, co nie jest monadą. Dobrze znanym przykładem czegoś, co nie jest monadą, jest ZipList
. I możemy stworzyć wariant, który uruchamia monadyczne działanie na każdym poziomie:
import Control.Applicative
import Control.Arrow ((***))
import Control.Monad
import Control.Monad.Trans
-- | A list where each step is produced by a monadic action.
data ListT m a = Nil | Cons (m (a, ListT m a))
To jest właściwie monadowy strumień. I może być łatwo przekształcony w Functor
i Applicative
instance Monad m => Functor (ListT m) where
fmap f Nil = Nil
fmap f (Cons k) = Cons $ (f *** fmap f) `liftM` k
instance Monad m => Applicative (ListT m) where
pure x = Cons $ return (x, pure x)
Cons mf <*> Cons mx = Cons $ do
(f, fs) <- mf
(x, xs) <- mx
return (f x, fs <*> xs)
_ <*> _ = Nil
ale oczywiście nie jest to monada. Mamy więc instancję MonadTrans
, która konwertuje monadę w coś, co jest tylko Applicative
.
instance MonadTrans ListT where
lift mx = Cons $ (\x -> (x, lift mx)) `liftM` mx
(To wszystko uświadomiło mi, że eksperymentalny ZipSink
w przewód-extra jest również ładny takich przykładów.)
Jednak to rodzi kolejne pytanie: jeśli chcemy takich transformatory, jakie prawa powinny przestrzegać? Przepisy prawne dotyczące MonadTrans
są zdefiniowane jako
lift . return = return
lift (m >>= f) = lift m >>= (lift . f)
Tak więc w naszym przypadku moglibyśmy chcieć czegoś jak
lift (f `liftM` x) = fmap f (lift x)
lift . return = pure
lift (m `ap` f) = lift m <*> lift f
Dlaczego chcesz, aby zapewnić wynik jest monada? Byłoby to zdecydowanie mniej ogólne i nie widzę z tego żadnej korzyści. –
@JohnL Przede wszystkim dlatego, że ['MonadTrans' praw] (http://hackage.haskell.org/packages/archive/transformers/0.3.0.0/doc/html/Control-Monad-Trans-Class.html#t:MonadTrans) wyrażone są monadycznie, więc wynik musi być monadą. Jeśli tak nie jest, praw nie można nawet wyrazić. Ale bheklilr dał dobry punkt w swojej odpowiedzi i na tej podstawie zrobiłem [przykład] (http://stackoverflow.com/a/18495255/1333025), który produkuje transformator 'Monad' ->' Applicative'. Oznacza to jednak, że musimy sformułować inny zestaw praw. –