packages feed

MonadCompose 0.6.0.0 → 0.7.0.0

raw patch · 3 files changed

+29/−43 lines, 3 files

Files

Control/Monad/IOT.hs view
@@ -4,14 +4,14 @@ 
 import GHC.IO hiding (liftIO)
 import GHC.Prim
-import Control.Monad.Trans -- (MonadIO(..))
+import Control.Monad.Trans (MonadIO(..))
 import Control.Monad.Identity
--- import Control.Monad.Morph
+import Control.Monad.Morph
 import Control.Monad
 import Control.Applicative
 import Unsafe.Coerce
 
-data St = St { unSt :: !(State# RealWorld) }
+data Ret a = Ret (State# RealWorld) a
 
 -- | An IO monad transformer.
 --
@@ -24,33 +24,20 @@ --
 -- Should be integrated with STT.
 
-class MFunctor t where
-    {-| Lift a monad morphism from @m@ to @n@ into a monad morphism from
-        @(t m)@ to @(t n)@
-    -}
-    hoist :: (Monad m) => (forall a . m a -> n a) -> t m b -> t n b
-
-class (MFunctor t, MonadTrans t) => MMonad t where
-    {-| Embed a newly created 'MMonad' layer within an existing layer
-
-        'embed' is analogous to ('=<<')
-    -}
-    embed :: (Monad n) => (forall a . m a -> t n a) -> t m b -> t n b
-
 data Sequence m where
 	None :: Sequence m
-	Seq :: (Monad m) => IO St -> Sequence (IOT m)
+	Seq :: (Monad m) => IO (Ret ()) -> Sequence (IOT m)
 
-{-#  INLINE runSequence #-}
-runSequence :: (Monad m) => Sequence m -> St -> m St
-runSequence None = return
-runSequence (Seq io) = \_ -> liftIO io
+{-# NOINLINE runSequence #-}
+runSequence :: (Monad m) => Sequence m -> State# RealWorld -> m (Ret ())
+runSequence None s = return (Ret s ())
+runSequence (Seq io) _ = liftIO io
 
-newtype IOT m t = IOT (Sequence m -> St -> m (St, t))
+newtype IOT m t = IOT (Sequence m -> State# RealWorld -> m (Ret t))
 
 instance (Monad m) => Monad (IOT m) where
-	return x = IOT (\_ s -> return (s, x))
-	IOT f >>= g = IOT (\i s -> f i s >>= \(s2, x) -> case g x of
+	return x = IOT (\_ s -> return (Ret s x))
+	IOT f >>= g = IOT (\i s -> f i s >>= \(Ret s2 x) -> case g x of
 		IOT h -> h i s2)
 
 instance (Monad m) => Applicative (IOT m) where
@@ -61,28 +48,25 @@ 	fmap f m = m >>= return . f
 
 instance (Monad m) => MonadIO (IOT m) where
-	liftIO (IO f) = IOT (\_ s -> case f (unSt s) of
-		(# s2, x #) -> return (St s2, x))
+	liftIO (IO f) = IOT (\_ s -> case f s of
+		(# s2, x #) -> return (Ret s2 x))
 
 instance MonadTrans IOT where
-	lift m = IOT (\i s -> m >>= \x -> liftM (\s -> (s, x)) (runSequence i s))
+	lift m = IOT (\i s -> m >>= \x -> liftM (\(Ret s ()) -> Ret s x) (runSequence i s))
 
 -- Flatten two layers into one. mmorph exports 'squash'.
 --
 -- Unsafely interleave actions in the outer monad, but sequence with the
 -- inner monad using a sequencing fn.
-_squash (IOT f) = IOT (\i s -> let IOT g = f (Seq $ IO $ \s -> (# s, St s #)) s in g i s >>= return . snd)
+_squash (IOT f) = IOT (\i s -> let IOT g = f (Seq $ IO $ \s -> (# s, Ret s () #)) s in g i s >>= \(Ret _ pr) -> return pr)
 
 _hoist :: (forall t. m t -> n t) -> IOT m t -> IOT n t
-_hoist f (IOT g) = IOT (\i -> f . g (unsafeCoerce i))
+_hoist f (IOT g) = IOT (\i s -> f (g (unsafeCoerce i) s))
 -- Type safety proof: the datum i is either in None or Seq.
 --   * If it is in None, it is valid at all types.
 --   * If it is in Seq, the only way it can be projected is from IOT m to IO
 --   and back again. liftIO is valid at both. So 'runSequence' will
 --   certainly be used at a valid type.
---
---   Here is the test of where things can go wrong:
-test = run $ _squash $ hoist (liftIO . run) $ liftIO (print "A") >> lift (liftIO (print "B"))
 
 instance MMonad IOT where
 	embed f = _squash . _hoist f
@@ -92,5 +76,5 @@ 
 -- | Run an IOT.
 run :: IOT Identity t -> IO t
-run (IOT f) = IO (\s -> case runIdentity (f None (St s)) of
-	(s2, x) -> (# unSt s2, x #))
+run (IOT f) = IO (\s -> case runIdentity (f None s) of
+	Ret s2 x -> (# s2, x #))
Control/Monad/Lifter.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE OverlappingInstances, FlexibleInstances, FlexibleContexts, MultiParamTypeClasses, UndecidableInstances #-}
+{-# LANGUAGE OverlappingInstances, FlexibleInstances, FlexibleContexts, MultiParamTypeClasses, UndecidableInstances, TypeOperators #-}
 
 module Control.Monad.Lifter where
 
@@ -6,6 +6,7 @@ import Control.Monad.ST
 import Control.Monad.Identity
 import Control.Monad.Morph
+import Control.Monad.PlusMonad
 
 -- | An automatic lifter. The idea of automatic lifting is due to Dan Piponi.
 class Lifter m n where
@@ -22,6 +23,9 @@ 
 instance Lifter Identity Identity where
 	lf = id
+
+instance Lifter m (m ::+ n) where
+	lf = inl
 
 instance (MonadTrans n, Monad x, Lifter m x) => Lifter m (n x) where
 	lf = lift . lf
MonadCompose.cabal view
@@ -1,15 +1,13 @@ name:                MonadCompose
-version:             0.6.0.0
+version:             0.7.0.0
 synopsis:            Methods for composing monads.
 description:         Methods for composing monads.
-
-  The IO monad transformer solves the problem of combining two IO-performing monad transformers, so that neither one needs to provide a MonadIO interface, and both can be transformed separately.
-
+  .
+  The IO monad transformer solves the problem of combining two IO-performing monads, so that neither one needs to provide a MonadIO interface and both can be transformed separately.
+  .
   Most known monads have a distributive law. The Distributive module implements distributivity for monad transformers.
-
-  A monad transformer can transform another monad, but if you have two monads both lacking a transformer, there is little you can do in general. However, you can compose them in a coproduct construction. The PlusMonad module implements a similar plan, but differs from coproducts in that it doesn't compress together contiguous uses of a monad. Another mystery is how to get the other distributive law (m(x + y) -> mx + my).
-
-  I would like the auto-lifter and the Plus monad to work together, but I can't figure out how to coax IncoherentInstances to support it.
+  .
+  A monad transformer can transform another monad, but if you have two monads both lacking a transformer, there is little you can do in general. However, you can compose them in a coproduct construction. The PlusMonad module implements a similar plan, but differs from coproducts in that it doesn't compress together contiguous uses of a monad.
 homepage:            http://alkalisoftware.net
 license:             BSD3
 license-file:        LICENSE