packages feed

MonadCompose 0.5.0.0 → 0.6.0.0

raw patch · 4 files changed

+130/−85 lines, 4 files

Files

Control/Monad/IOT.hs view
@@ -1,14 +1,15 @@-{-# LANGUAGE MagicHash, UnboxedTuples, Rank2Types #-}
+{-# LANGUAGE MagicHash, UnboxedTuples, Rank2Types, GADTs #-}
 
 module Control.Monad.IOT (IOT, run) where
 
 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) }
 
@@ -23,12 +24,34 @@ --
 -- Should be integrated with STT.
 
-newtype IOT m t = IOT (St -> m (St, t))
+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)
+
+{-#  INLINE runSequence #-}
+runSequence :: (Monad m) => Sequence m -> St -> m St
+runSequence None = return
+runSequence (Seq io) = \_ -> liftIO io
+
+newtype IOT m t = IOT (Sequence m -> St -> m (St, t))
+
 instance (Monad m) => Monad (IOT m) where
-	return x = IOT (\s -> return (s, x))
-	IOT f >>= g = IOT (\s -> f s >>= \(s2, x) -> case g x of
-		IOT h -> h s2)
+	return x = IOT (\_ s -> return (s, x))
+	IOT f >>= g = IOT (\i s -> f i s >>= \(s2, x) -> case g x of
+		IOT h -> h i s2)
 
 instance (Monad m) => Applicative (IOT m) where
 	pure = return
@@ -38,22 +61,36 @@ 	fmap f m = m >>= return . f
 
 instance (Monad m) => MonadIO (IOT m) where
-	liftIO (IO f) = IOT (\s -> case f (unSt s) of
+	liftIO (IO f) = IOT (\_ s -> case f (unSt s) of
 		(# s2, x #) -> return (St s2, x))
 
 instance MonadTrans IOT where
-	lift m = IOT (\s -> liftM ((,) s) m)
-
-instance MFunctor IOT where
-	hoist f (IOT g) = IOT (f . g)
+	lift m = IOT (\i s -> m >>= \x -> liftM (\s -> (s, x)) (runSequence i s))
 
 -- Flatten two layers into one. mmorph exports 'squash'.
-_squash (IOT f) = IOT (\s -> let IOT g = f s in g s >>= return . snd)
+--
+-- 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)
 
+_hoist :: (forall t. m t -> n t) -> IOT m t -> IOT n t
+_hoist f (IOT g) = IOT (\i -> f . g (unsafeCoerce i))
+-- 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 (IOT g) = _squash $ IOT (f . g)
+	embed f = _squash . _hoist f
 
+instance MFunctor IOT where
+	hoist = _hoist
+
 -- | Run an IOT.
 run :: IOT Identity t -> IO t
-run (IOT f) = IO (\s -> case runIdentity (f (St s)) of
+run (IOT f) = IO (\s -> case runIdentity (f None (St s)) of
 	(s2, x) -> (# unSt s2, x #))
− Control/Monad/Plus.hs
@@ -1,67 +0,0 @@-{-# LANGUAGE RankNTypes, TypeOperators #-}
-
--- | The Plus monad - a free combination of monads. This is very similar to coproducts, but not quite the same.
---
---   Coproducts are due to Luth and Ghani, "Composing Monads Using Coproducts," http://www.informatik.uni-bremen.de/~cxl/papers/icfp02.pdf
-module Control.Monad.Plus where
-
-import Control.Monad.Trans
-import Control.Monad.Identity
-import Control.Monad.Product
-import Control.Monad.Morph
-import Control.Applicative
-import Control.Arrow
-
-newtype (m ::+ n) t = Plus { unPlus :: forall x. (MonadPlus x) => (forall u. m u -> x u) -> (forall u. n u -> x u) -> x t }
-
-instance Monad (m ::+ n) where
-	return x = Plus (\_ _ -> return x)
-	Plus f >>= g = Plus (\h i -> f h i >>= \x -> unPlus (g x) h i)
-
-instance Functor (m ::+ n) where
-	fmap f m = m >>= return . f
-
-instance Applicative (m ::+ n) where
-	pure = return
-	(<*>) = ap
-
-instance MonadPlus (m ::+ n) where
-	mzero = Plus (\_ _ -> mzero)
-	mplus (Plus f) (Plus g) = Plus (\h i -> mplus (f h i) (g h i))
-
-instance Alternative (m ::+ n) where
-	empty = mzero
-	(<|>) = mplus
-
-inl m = Plus (\h _ -> h m)
-
-inr m = Plus (\_ i -> i m)
-
-instance MonadTrans ((::+) m) where
-	lift = inr
-
-mapPlus :: (forall t. m t -> m1 t) -> (forall t. n t -> n1 t) -> (m ::+ n) t -> (m1 ::+ n1) t
-mapPlus f g (Plus x) = Plus (\h i -> x (h . f) (i . g))
-
-instance MFunctor ((::+) m) where
-	hoist = mapPlus id
-
-comm :: (m ::+ n) t -> (n ::+ m) t
-comm (Plus f) = Plus (\h i -> f i h)
-
-assoc (Plus f) = Plus (\h i -> f (\m -> unPlus m h (i . inl)) (i . inr))
-
-assoc1 (Plus f) = Plus (\h i -> f (h . inl) (\m -> unPlus m (h . inr) i))
-
-cancelLeft (Plus f) = f (return . runIdentity) id
-
-cancelRight (Plus f) = f id (return . runIdentity)
-
-refl (Plus f) = f id id
-
-instance (MonadPlus m) => MMonad ((::+) m) where
-	embed f = mapPlus refl id . assoc1 . mapPlus id f
-
--- | Distributivity with monad products.
-distr pls = Product (mapPlus (fst . runProduct) (fst . runProduct) pls, mapPlus (snd . runProduct) (snd . runProduct) pls)
-
+ Control/Monad/PlusMonad.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE RankNTypes, TypeOperators #-}
+
+-- | The Plus monad - a free combination of monads. This is very similar to coproducts, but not quite the same.
+--
+--   Coproducts are due to Luth and Ghani, "Composing Monads Using Coproducts," http://www.informatik.uni-bremen.de/~cxl/papers/icfp02.pdf
+module Control.Monad.PlusMonad where
+
+import Control.Monad.Trans
+import Control.Monad.Identity
+import Control.Monad.Product
+import Control.Monad.Morph
+import Control.Applicative
+import Control.Arrow
+
+newtype (m ::+ n) t = Plus { unPlus :: forall x. (MonadPlus x) => (forall u. m u -> x u) -> (forall u. n u -> x u) -> x t }
+
+instance Monad (m ::+ n) where
+	return x = Plus (\_ _ -> return x)
+	Plus f >>= g = Plus (\h i -> f h i >>= \x -> unPlus (g x) h i)
+
+instance Functor (m ::+ n) where
+	fmap f m = m >>= return . f
+
+instance Applicative (m ::+ n) where
+	pure = return
+	(<*>) = ap
+
+instance MonadPlus (m ::+ n) where
+	mzero = Plus (\_ _ -> mzero)
+	mplus (Plus f) (Plus g) = Plus (\h i -> mplus (f h i) (g h i))
+
+instance Alternative (m ::+ n) where
+	empty = mzero
+	(<|>) = mplus
+
+inl m = Plus (\h _ -> h m)
+
+inr m = Plus (\_ i -> i m)
+
+instance MonadTrans ((::+) m) where
+	lift = inr
+
+mapPlus :: (forall t. m t -> m1 t) -> (forall t. n t -> n1 t) -> (m ::+ n) t -> (m1 ::+ n1) t
+mapPlus f g (Plus x) = Plus (\h i -> x (h . f) (i . g))
+
+instance MFunctor ((::+) m) where
+	hoist = mapPlus id
+
+comm :: (m ::+ n) t -> (n ::+ m) t
+comm (Plus f) = Plus (\h i -> f i h)
+
+assoc (Plus f) = Plus (\h i -> f (\m -> unPlus m h (i . inl)) (i . inr))
+
+assoc1 (Plus f) = Plus (\h i -> f (h . inl) (\m -> unPlus m (h . inr) i))
+
+cancelLeft (Plus f) = f (return . runIdentity) id
+
+cancelRight (Plus f) = f id (return . runIdentity)
+
+refl (Plus f) = f id id
+
+instance (MonadPlus m) => MMonad ((::+) m) where
+	embed f = mapPlus refl id . assoc1 . mapPlus id f
+
+-- | Distributivity with monad products.
+distr pls = Product (mapPlus (fst . runProduct) (fst . runProduct) pls, mapPlus (snd . runProduct) (snd . runProduct) pls)
+
MonadCompose.cabal view
@@ -1,7 +1,15 @@ name:                MonadCompose
-version:             0.5.0.0
+version:             0.6.0.0
 synopsis:            Methods for composing monads.
-description:         Methods for composing monads, including an IO monad transformer.
+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.
+
+  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.
 homepage:            http://alkalisoftware.net
 license:             BSD3
 license-file:        LICENSE
@@ -13,6 +21,6 @@ cabal-version:       >=1.8
 
 library
-  exposed-modules:     Control.Monad.IOT, Control.Monad.Distributive, Control.Monad.Plus, Control.Monad.Lifter
+  exposed-modules:     Control.Monad.IOT, Control.Monad.Distributive, Control.Monad.PlusMonad, Control.Monad.Lifter
   -- other-modules: 
   build-depends:       base >=4 && <=5, ghc-prim ==0.3.*, mtl ==2.1.*, mmorph ==1.0.*, monad-products, transformers, MaybeT