packages feed

objective 0.6.3.2 → 0.6.3.3

raw patch · 12 files changed

+546/−492 lines, 12 filesdep +comonaddep +voiddep −transformers-compatdep ~transformers

Dependencies added: comonad, void

Dependencies removed: transformers-compat

Dependency ranges changed: transformers

Files

objective.cabal view
@@ -1,5 +1,5 @@ name:                objective
-version:             0.6.3.2
+version:             0.6.3.3
 synopsis:            Extensible objects
 description:         Stateful effect transducer
 homepage:            https://github.com/fumieval/objective
@@ -16,16 +16,23 @@ cabal-version:       >=1.10
 
 library
-  exposed-modules:     Control.Object
-                     , Control.Monad.Objective
-                     , Control.Monad.Objective.Class
-                     , Control.Monad.Objective.IO
-                     , Control.Monad.Objective.ST
-                     , Data.Functor.Request
-                     , Data.Functor.PushPull
+  exposed-modules:
+    Control.Object
+      , Control.Object.Object
+      , Control.Object.Mortal
+      , Control.Object.Process
+      , Control.Object.Extra
+      , Control.Object.Stream
+      , Control.Monad.Objective
+      , Control.Monad.Objective.Class
+      , Control.Monad.Objective.IO
+      , Control.Monad.Objective.ST
+      , Data.Functor.Request
+      , Data.Functor.PushPull
   -- other-modules:
   other-extensions:    MultiParamTypeClasses, KindSignatures, TypeFamilies
   build-depends:       base >=4.5 && <5
+    , comonad
     , clean-unions < 0.2
     , elevator >= 0.1.2 && <0.2
     , containers
@@ -37,9 +44,9 @@     , unordered-containers
     , hashable >= 1.2 && <1.4
     , either
+    , void
     , adjunctions >= 4.0 && <5
-    , transformers >= 0.2 && <0.5
-    , transformers-compat >= 0.3
+    , transformers >= 0.3 && <0.5
   ghc-options: -Wall
   hs-source-dirs:      src
   default-language:    Haskell2010
src/Control/Monad/Objective/Class.hs view
@@ -21,7 +21,7 @@ --
 -----------------------------------------------------------------------------
 module Control.Monad.Objective.Class where
-import Control.Object
+import Control.Object.Object
 import Control.Elevator
 import Control.Monad.Trans.State.Strict
 import Control.Monad.Operational.Mini
src/Control/Monad/Objective/IO.hs view
@@ -16,7 +16,7 @@ module Control.Monad.Objective.IO  where
 import Control.Monad.Objective.Class
 import Control.Concurrent
-import Control.Object
+import Control.Object.Object
 import Control.Monad.IO.Class
 
 instance ObjectiveBase IO where
src/Control/Monad/Objective/ST.hs view
@@ -18,7 +18,7 @@ 
 import Control.Monad.Objective.Class
 import Control.Monad.ST
-import Control.Object
+import Control.Object.Object
 import Data.STRef
 import Control.Elevator
 
src/Control/Object.hs view
@@ -1,7 +1,6 @@+{-# LANGUAGE Trustworthy #-}
 {-# LANGUAGE Rank2Types, FlexibleInstances, FlexibleContexts, TypeOperators, CPP, ConstraintKinds #-}
-#if __GLASGOW_HASKELL__ >= 707
-{-# LANGUAGE DeriveDataTypeable #-}
-#endif
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Object
@@ -15,481 +14,20 @@ -- Stateful effect transducer: The Mealy machine for effects.
 --
 -----------------------------------------------------------------------------
-module Control.Object (
-  -- * Construction
-  Object(..),
-  (@-),
-  liftO,
-  echo,
-  oneshot,
-  stateful,
-  variable,
-  Variable,
-  unfoldO,
-  unfoldOM,
-  foldP,
-  foldP',
-  sharing,
-  animate,
-  transit,
-  -- * Composition
-  (@>>@),
-  (@>>^),
-  (^>>@),
-  (@**@),
-  (@||@),
-  loner,
-  (@|>@),
-  transObject,
-  adaptObject,
-  -- * Stream
-  ($$),
-  ($$!),
-  (!$$),
-  (!$$!),
-  -- * Monads
-  (@!),
-  (@!!),
-  sequential,
-  sequentialT,
-  iterObject,
-  iterTObject,
-  iterative,
-  iterativeT,
-  -- * Patterns
-  flyweight,
-  flyweight',
-  announce,
-  announceMaybe,
-  announceMaybeT,
-  announceMortal,
-  Process(..),
-  _Process,
-  Mortal(..),
-  runMortal,
-  )
-where
+module Control.Object
+  ( module Control.Object.Object,
+    module Control.Object.Stream,
+    module Control.Object.Mortal,
+    module Control.Object.Process,
+    module Control.Object.Extra,
+    module Data.Functor.Request,
+    module Data.Functor.PushPull
+  ) where
 
-import Control.Applicative
-import Control.Arrow as A
-import Control.Elevator
-import Control.Monad
-import Control.Monad.Free
-import Control.Monad.Operational.Mini
-import Control.Monad.Trans.Class
-import Control.Monad.Trans.Maybe
-import Control.Monad.Trans.State.Strict
-import Control.Monad.Trans.Writer.Strict
-import Data.Functor.Day
-import Data.Functor.PushPull
+import Control.Object.Object
+import Control.Object.Stream
+import Control.Object.Mortal
+import Control.Object.Process
+import Control.Object.Extra
 import Data.Functor.Request
-import Data.Functor.Sum as F
-import Data.Hashable
-import Data.Monoid
-import Data.OpenUnion1.Clean
-import Data.Profunctor
-import Data.Typeable
-import Data.Witherable
-import qualified Control.Category as C
-import qualified Control.Monad.Trans.Free as T
-import qualified Control.Monad.Trans.Operational.Mini as T
-import qualified Data.HashMap.Strict as HM
-import qualified Data.Map.Strict as Map
-import qualified Data.Traversable as T
-import Control.Monad.Trans.Either as E
-import Unsafe.Coerce
-
-import Data.Functor.Rep
-import Data.Functor.Adjunction
-
--- | The type @Object f g@ represents objects which can handle messages @f@, perform actions in the environment @g@.
--- It can be thought of as an automaton that converts effects.
--- 'Object's can be composed just like functions using '@>>@'; the identity element is 'echo'.
--- Objects are morphisms of the category of functors
-newtype Object f g = Object { runObject :: forall x. f x -> g (x, Object f g) }
-#if __GLASGOW_HASKELL__ >= 707
-  deriving (Typeable)
-#else
-instance (Typeable1 f, Typeable1 g) => Typeable (Object f g) where
-  typeOf t = mkTyConApp objectTyCon [typeOf1 (f t), typeOf1 (g t)] where
-    f :: Object f g -> f a
-    f = undefined
-    g :: Object f g -> g a
-    g = undefined
-
-objectTyCon :: TyCon
-#if __GLASGOW_HASKELL__ < 704
-objectTyCon = mkTyCon "Control.Object.Object"
-#else
-objectTyCon = mkTyCon3 "object" "Control.Object" "Object"
-#endif
-{-# NOINLINE objectTyCon #-}
-#endif
-
--- | An alias for 'runObject'.
-(@-) :: Object f g -> f x -> g (x, Object f g)
-(@-) = runObject
-{-# INLINE (@-) #-}
-infixr 3 @-
-
--- | The identity object
-echo :: Functor f => Object f f
-echo = Object (fmap (\x -> (x, echo)))
-
--- | Object-object composition
-(@>>@) :: Functor h => Object f g -> Object g h -> Object f h
-Object m @>>@ Object n = Object $ fmap (\((x, m'), n') -> (x, m' @>>@ n')) . n . m
-infixr 1 @>>@
-
--- | Object-function composition
-(@>>^) :: Functor h => Object f g -> (forall x. g x -> h x) -> Object f h
-m0 @>>^ g = go m0 where go (Object m) = Object $ fmap (fmap go) . g . m
-infixr 1 @>>^
-
--- | Function-object composition
-(^>>@) :: Functor h => (forall x. f x -> g x) -> Object g h -> Object f h
-f ^>>@ m0 = go m0 where go (Object m) = Object $ fmap (fmap go) . m . f
-infixr 1 ^>>@
-
-(@**@) :: Applicative m => Object f m -> Object g m -> Object (Day f g) m
-a @**@ b = Object $ \(Day f g r) -> (\(x, a') (y, b') -> (r x y, a' @**@ b')) <$> runObject a f <*> runObject b g
-infixr 3 @**@
-
-(@||@) :: Functor m => Object f m -> Object g m -> Object (F.Sum f g) m
-a @||@ b = Object $ \r -> case r of
-  InL f -> fmap (fmap (@||@b)) (runObject a f)
-  InR g -> fmap (fmap (a@||@)) (runObject b g)
-infixr 2 @||@
-
--- | Lift a natural transformation into an object.
-liftO :: Functor g => (forall x. f x -> g x) -> Object f g
-liftO f = go where go = Object $ fmap (\x -> (x, go)) . f
-{-# INLINE liftO #-}
-
--- | Change the workspace of the object.
-transObject :: Functor g => (forall x. f x -> g x) -> Object e f -> Object e g
-transObject f = (@>>^f)
-
--- | Apply a function to the messages coming into the object.
-adaptObject :: Functor m => (forall x. g x -> f x) -> Object f m -> Object g m
-adaptObject f = (f^>>@)
-
--- | Build an object using continuation passing style.
-oneshot :: (Functor f, Monad m) => (forall a. f (m a) -> m a) -> Object f m
-oneshot m = go where
-  go = Object $ \e -> m (fmap return e) >>= \a -> return (a, go)
-{-# INLINE oneshot #-}
-
--- | Build a stateful object.
---
--- @stateful t s = t ^>>@ variable s@
-stateful :: Monad m => (forall a. f a -> StateT s m a) -> s -> Object f m
-stateful h = go where
-  go s = Object $ liftM (\(a, s') -> (a, go s')) . flip runStateT s . h
-{-# INLINE stateful #-}
-
--- | The unwrapped analog of 'stateful'
---     @unfoldO runObject = id@
---     @unfoldO runSequential = sequential@
---     @unfoldO iterObject = iterable@
-unfoldO :: Functor g => (forall a. r -> f a -> g (a, r)) -> r -> Object f g
-unfoldO h = go where go r = Object $ fmap (fmap go) . h r
-{-# INLINE unfoldO #-}
-
-unfoldOM :: Monad m => (forall a. r -> f a -> m (a, r)) -> r -> Object f m
-unfoldOM h = go where go r = Object $ liftM (fmap go) . h r
-{-# INLINE unfoldOM #-}
-
-type Variable s = forall m. Monad m => Object (StateT s m) m
-
--- | A mutable variable.
-variable :: s -> Variable s
-variable s = Object $ \m -> liftM (fmap variable) $ runStateT m s
-
--- | Build a stateful object, sharing out the state.
-sharing :: Monad m => (forall a. f a -> StateT s m a) -> s -> Object (State s |> f |> Nil) m
-sharing m = go where
-  go s = Object $ \k -> liftM (fmap go) $ ($k)
-    $ (\n -> return $ runState n s)
-    ||> (\e -> runStateT (m e) s)
-    ||> exhaust
-{-# INLINE sharing #-}
-
--- | An object that won't accept any messages.
-loner :: Functor f => Object Nil f
-loner = liftO exhaust
-
--- | Extend an object by adding another independent object.
-(@|>@) :: Functor g => Object f g -> Object (Union s) g -> Object (f |> Union s) g
-p @|>@ q = Object $ fmap (fmap (@|>@q)) . runObject p ||> fmap (fmap (p @|>@)) . runObject q
-infixr 3 @|>@
-
--- | The flyweight pattern.
-flyweight :: (Monad m, Ord k) => (k -> m a) -> Object (Request k a) m
-flyweight f = go Map.empty where
-  go m = Object $ \(Request k cont) -> case Map.lookup k m of
-    Just a -> return (cont a, go m)
-    Nothing -> f k >>= \a -> return (cont a, go $ Map.insert k a m)
-
--- | Like 'flyweight', but it uses 'Data.HashMap.Strict' internally.
-flyweight' :: (Monad m, Eq k, Hashable k) => (k -> m a) -> Object (Request k a) m
-flyweight' f = go HM.empty where
-  go m = Object $ \(Request k cont) -> case HM.lookup k m of
-    Just a -> return (cont a, go m)
-    Nothing -> f k >>= \a -> return (cont a, go $ HM.insert k a m)
-
-(@!) :: Monad m => Object e m -> ReifiedProgram e a -> m (a, Object e m)
-obj @! Return a = return (a, obj)
-obj @! (e :>>= cont) = runObject obj e >>= \(a, obj') -> obj' @! cont a
-infixr 3 @!
-
-(@!!) :: Monad m => Object e m -> T.ReifiedProgramT e m a -> m (a, Object e m)
-obj @!! T.Return a = return (a, obj)
-obj @!! T.Lift m cont = m >>= (obj @!!) . cont
-obj @!! (e T.:>>= cont) = runObject obj e >>= \(a, obj') -> obj' @!! cont a
-infixr 3 @!!
-
-iterObject :: Monad m => Object f m -> Free f a -> m (a, Object f m)
-iterObject obj (Pure a) = return (a, obj)
-iterObject obj (Free f) = runObject obj f >>= \(cont, obj') -> iterObject obj' cont
-
-iterTObject :: Monad m => Object f m -> T.FreeT f m a -> m (a, Object f m)
-iterTObject obj m = T.runFreeT m >>= \r -> case r of
-  T.Pure a -> return (a, obj)
-  T.Free f -> runObject obj f >>= \(cont, obj') -> iterTObject obj' cont
-
--- | Let object handle sequential methods.
-sequential :: Monad m => Object e m -> Object (ReifiedProgram e) m
-sequential = unfoldOM (@!)
-
--- | Let object handle sequential methods.
-sequentialT :: Monad m => Object e m -> Object (T.ReifiedProgramT e m) m
-sequentialT = unfoldOM (@!!)
-
-iterative :: Monad m => Object f m -> Object (Free f) m
-iterative = unfoldOM iterObject
-
-iterativeT :: Monad m => Object f m -> Object (T.FreeT f m) m
-iterativeT = unfoldOM iterTObject
-
-foldP :: Applicative f => (a -> r -> f r) -> r -> Object (PushPull a r) f
-foldP f = go where
-  go r = Object $ \pp -> case pp of
-    Push a c -> fmap (\z -> (c, z `seq` go z)) (f a r)
-    Pull cont -> pure (cont r, go r)
-{-# INLINE foldP #-}
-
-foldP' :: Applicative f => (a -> r -> r) -> r -> Object (PushPull a r) f
-foldP' f = go where
-  go r = Object $ \pp -> case pp of
-    Push a c -> let z = f a r in pure (c, z `seq` go z)
-    Pull cont -> pure (cont r, go r)
-{-# INLINE foldP' #-}
-
-animate :: (Applicative m, Num t) => (t -> m a) -> Object (Request t a) m
-animate f = go 0 where
-  go t = Object $ \(Request dt cont) -> (\x -> (cont x, go (t + dt))) <$> f t
-
-transit :: (Alternative m, Fractional t, Ord t) => t -> (t -> m a) -> Object (Request t a) m
-transit len f = go 0 where
-  go t
-    | t >= len = Object $ const empty
-    | otherwise = Object $ \(Request dt cont) -> (\x -> (cont x, go (t + dt))) <$> f (t / len)
-
-announce :: (T.Traversable t, Monad m, Elevate (State (t (Object f g))) m, Elevate g m) => f a -> m [a]
-announce f = do
-  t <- elevate get
-  (t', Endo e) <- runWriterT $ T.mapM (\obj -> (lift . elevate) (runObject obj f)
-      >>= \(x, obj') -> writer (obj', Endo (x:))) t
-  elevate (put t')
-  return (e [])
-
-announceMaybe :: (Witherable t
-    , Monad m
-    , Elevate (State (t (Object f Maybe))) m) => f a -> m [a]
-announceMaybe f = elevate $ state
-  $ \t -> let (t', Endo e) = runWriter
-                $ witherM (\obj -> case runObject obj f of
-                  Just (x, obj') -> lift $ writer (obj', Endo (x:))
-                  Nothing -> mzero) t in (e [], t')
-
-announceMaybeT :: (Witherable t
-  , Monad m
-  , State (t (Object f (MaybeT g))) ∈ Floors1 m
-  , g ∈ Floors1 m
-  , Tower m) => f a -> m [a]
-announceMaybeT f = do
-  t <- elevate get
-  (t', Endo e) <- runWriterT $ witherM (\obj -> mapMaybeT (lift . elevate) (runObject obj f)
-      >>= \(x, obj') -> lift (writer (obj', Endo (x:)))) t
-  elevate (put t')
-  return (e [])
-
-announceMortal :: (Witherable t
-  , Monad m
-  , State (t (Mortal f g ())) ∈ Floors1 m
-  , g ∈ Floors1 m
-  , Tower m) => f a -> m [a]
-announceMortal f = do
-  t <- elevate get
-  (t', Endo e) <- runWriterT $ witherM (\obj -> MaybeT (lift $ liftM is $ elevate $ runMortal obj f)
-      >>= \(x, obj') -> lift (writer (obj', Endo (x:)))) t
-  elevate (put t')
-  return (e [])
-  where
-    is (Left ()) = Nothing
-    is (Right a) = Just a
-
--- | An object which is specialized to be a Mealy machine
-newtype Process m a b = Process { unProcess :: Object (Request a b) m }
-
--- | @_Process :: Iso' (Object (Request a b) m) (Process m a b)@
-_Process :: (Profunctor p, Functor f) => p (Process m a b) (f (Process m a b)) -> p (Object (Request a b) m) (f (Object (Request a b) m))
-_Process = dimap Process (fmap unProcess)
-
-instance Functor f => Functor (Process f a) where
-  fmap f (Process o0) = Process $ go o0 where
-    go o = Object $ \(Request a cont) -> fmap (cont *** go) $ runObject o (Request a f)
-
-instance Applicative f => Applicative (Process f a) where
-  pure a = Process go where
-    go = Object $ \(Request _ cont) -> pure (cont a, go)
-  Process f0 <*> Process a0 = Process $ go f0 a0 where
-    go mf ma = Object $ \(Request a cont) -> (\(f, mf') (x, ma') -> (cont (f x), go mf' ma'))
-      <$> runObject mf (Request a id)
-      <*> runObject ma (Request a id)
-
-instance (Applicative f, Monoid b) => Monoid (Process f a b) where
-  mempty = pure mempty
-  mappend = liftA2 mappend
-
-instance Monad m => C.Category (Process m) where
-  id = arr id
-  Process g0 . Process f0 = Process $ go f0 g0 where
-    go f g = Object $ \(Request a cont) -> runObject f (Request a id)
-      >>= \(b, f') -> liftM (\(c, g') -> (cont c, go f' g')) $ runObject g (Request b id)
-
-instance Monad m => Arrow (Process m) where
-  arr f = Process go where
-    go = Object $ \(Request a cont) -> return (cont (f a), go)
-  first (Process f0) = Process $ go f0 where
-    go f = Object $ \(Request (a, c) cont) -> liftM (\(b, f') -> (cont (b, c), go f')) $ runObject f (Request a id)
-  second (Process f0) = Process $ go f0 where
-    go f = Object $ \(Request (a, c) cont) -> liftM (\(d, f') -> (cont (a, d), go f')) $ runObject f (Request c id)
-
-instance Monad m => ArrowChoice (Process m) where
-  left (Process f0) = Process $ go f0 where
-    go f = Object $ \(Request e cont) -> case e of
-      Left a -> liftM (\(b, f') -> (cont (Left b), go f')) $ runObject f (Request a id)
-      Right c -> return (cont (Right c), go f)
-  right (Process f0) = Process $ go f0 where
-    go f = Object $ \(Request e cont) -> case e of
-      Right a -> liftM (\(b, f') -> (cont (Right b), go f')) $ runObject f (Request a id)
-      Left c -> return (cont (Left c), go f)
-
-instance Monad m => Profunctor (Process m) where
-  dimap f g (Process f0) = Process (go f0) where
-    go m = Object $ \(Request a cont) -> liftM (\(b, m') -> (cont (g b), go m')) $ runObject m (Request (f a) id)
-  {-# INLINE dimap #-}
-
-instance Monad m => Strong (Process m) where
-  first' = first
-  {-# INLINE first' #-}
-  second' = second
-  {-# INLINE second' #-}
-
-instance Monad m => Choice (Process m) where
-  left' = A.left
-  {-# INLINE left' #-}
-  right' = A.right
-  {-# INLINE right' #-}
-
-instance (Applicative m, Num o) => Num (Process m i o) where
-  (+) = liftA2 (+)
-  {-# INLINE (+) #-}
-  (-) = liftA2 (-)
-  {-# INLINE (-) #-}
-  (*) = liftA2 (*)
-  {-# INLINE (*) #-}
-  abs = fmap abs
-  {-# INLINE abs #-}
-  signum = fmap signum
-  {-# INLINE signum #-}
-  fromInteger = pure . fromInteger
-  {-# INLINE fromInteger #-}
-
-instance (Applicative m, Fractional o) => Fractional (Process m i o) where
-  (/) = liftA2 (/)
-  {-# INLINE (/) #-}
-  recip = fmap recip
-  fromRational = pure . fromRational
-
--- | Object with a final result.
---
--- @Object f g ≡ Mortal f g Void@
---
-newtype Mortal f g a = Mortal { unMortal :: Object f (EitherT a g) }
-
-instance (Functor m, Monad m) => Functor (Mortal f m) where
-  fmap f (Mortal obj) = Mortal (obj @>>^ bimapEitherT f id)
-
-instance (Functor m, Monad m) => Applicative (Mortal f m) where
-  pure = return
-  (<*>) = ap
-
-instance Monad m => Monad (Mortal f m) where
-  return a = mortal $ const $ E.left a
-  m >>= k = mortal $ \f -> lift (runMortal m f) >>= \r -> case r of
-    Left a -> EitherT $ runMortal (k a) f
-    Right (x, m') -> return (x, m' >>= k)
-
-mortal :: (forall x. f x -> EitherT a m (x, Mortal f m a)) -> Mortal f m a
-mortal f = unsafeCoerce f
-{-# INLINE mortal #-}
-
-runMortal :: Mortal f m a -> f x -> m (Either a (x, Mortal f m a))
-runMortal = unsafeCoerce
-{-# INLINE runMortal #-}
-
--- | For every adjunction f ⊣ g, we can "connect" @Object g m@ and @Object f m@ permanently.
-($$) :: (Monad m, Adjunction f g) => Object g m -> Object f m -> m x
-a $$ b = do
-  (x, a') <- runObject a askRep
-  ((), b') <- runObject b (unit () `index` x)
-  a' $$ b'
-infix 0 $$
-
--- | Like '$$', but kept until the right 'Mortal' dies.
-($$!) :: (Monad m, Adjunction f g) => Object g m -> Mortal f m a -> m (Object g m, a)
-o $$! m = do
-  (x, o') <- runObject o askRep
-  r <- runMortal m (unit () `index` x)
-  case r of
-    Left a -> return (o', a)
-    Right ((), m') -> o' $$! m'
-infix 0 $$!
-
--- | Like '$$', but kept until the left 'Mortal' dies.
-(!$$) :: (Monad m, Adjunction f g) => Mortal g m a -> Object f m -> m (a, Object f m)
-m !$$ o = do
-  r <- runMortal m askRep
-  case r of
-    Left a -> return (a, o)
-    Right (x, m') -> do
-      ((), o') <- runObject o (unit () `index` x)
-      m' !$$ o'
-infix 0 !$$
-
--- | Connect two 'Mortal's.
-(!$$!) :: (Monad m, Adjunction f g) => Mortal g m a -> Mortal f m b -> m (Either (a, Mortal f m b) (Mortal g m a, b))
-m !$$! n = do
-  r <- runMortal m askRep
-  case r of
-    Left a -> return (Left (a, n))
-    Right (x, m') -> do
-      s <- runMortal n (unit () `index` x)
-      case s of
-        Left b -> return (Right (m', b))
-        Right ((), n') -> m' !$$! n'
-
-infix 0 !$$!
+import Data.Functor.PushPull
+ src/Control/Object/Extra.hs view
@@ -0,0 +1,114 @@+{-# LANGUAGE Rank2Types, TypeOperators, FlexibleContexts, ConstraintKinds #-}+module Control.Object.Extra where+import Control.Object.Object+import Control.Object.Mortal+import qualified Data.HashMap.Strict as HM+import qualified Data.Map.Strict as Map+import Data.Witherable+import Control.Monad.Trans.Maybe+import Control.Monad.Trans.Writer.Strict+import Control.Monad.Trans.State.Strict+import Control.Monad.Trans.Class+import Control.Monad+import Control.Elevator+import Data.Functor.Request+import Data.Functor.PushPull+import Control.Applicative+import Data.OpenUnion1.Clean+import Data.Monoid+import Data.Hashable+import Data.Traversable as T++-- | Build an object using continuation passing style.+oneshot :: (Functor f, Monad m) => (forall a. f (m a) -> m a) -> Object f m+oneshot m = go where+  go = Object $ \e -> m (fmap return e) >>= \a -> return (a, go)+{-# INLINE oneshot #-}++-- | The flyweight pattern.+flyweight :: (Monad m, Ord k) => (k -> m a) -> Object (Request k a) m+flyweight f = go Map.empty where+  go m = Object $ \(Request k cont) -> case Map.lookup k m of+    Just a -> return (cont a, go m)+    Nothing -> f k >>= \a -> return (cont a, go $ Map.insert k a m)++-- | Like 'flyweight', but it uses 'Data.HashMap.Strict' internally.+flyweight' :: (Monad m, Eq k, Hashable k) => (k -> m a) -> Object (Request k a) m+flyweight' f = go HM.empty where+  go m = Object $ \(Request k cont) -> case HM.lookup k m of+    Just a -> return (cont a, go m)+    Nothing -> f k >>= \a -> return (cont a, go $ HM.insert k a m)++animate :: (Applicative m, Num t) => (t -> m a) -> Object (Request t a) m+animate f = go 0 where+  go t = Object $ \(Request dt cont) -> (\x -> (cont x, go (t + dt))) <$> f t++transit :: (Alternative m, Fractional t, Ord t) => t -> (t -> m a) -> Object (Request t a) m+transit len f = go 0 where+  go t+    | t >= len = Object $ const empty+    | otherwise = Object $ \(Request dt cont) -> (\x -> (cont x, go (t + dt))) <$> f (t / len)++announce :: (T.Traversable t, Monad m, Elevate (State (t (Object f g))) m, Elevate g m) => f a -> m [a]+announce f = do+  t <- elevate get+  (t', Endo e) <- runWriterT $ T.mapM (\obj -> (lift . elevate) (runObject obj f)+      >>= \(x, obj') -> writer (obj', Endo (x:))) t+  elevate (put t')+  return (e [])++announceMaybe :: (Witherable t+    , Monad m+    , Elevate (State (t (Object f Maybe))) m) => f a -> m [a]+announceMaybe f = elevate $ state+  $ \t -> let (t', Endo e) = runWriter+                $ witherM (\obj -> case runObject obj f of+                  Just (x, obj') -> lift $ writer (obj', Endo (x:))+                  Nothing -> mzero) t in (e [], t')++announceMaybeT :: (Witherable t+  , Monad m+  , State (t (Object f (MaybeT g))) ∈ Floors1 m+  , g ∈ Floors1 m+  , Tower m) => f a -> m [a]+announceMaybeT f = do+  t <- elevate get+  (t', Endo e) <- runWriterT $ witherM (\obj -> mapMaybeT (lift . elevate) (runObject obj f)+      >>= \(x, obj') -> lift (writer (obj', Endo (x:)))) t+  elevate (put t')+  return (e [])++announceMortal :: (Witherable t+  , Monad m+  , State (t (Mortal f g ())) ∈ Floors1 m+  , g ∈ Floors1 m+  , Tower m) => f a -> m [a]+announceMortal f = do+  t <- elevate get+  (t', Endo e) <- runWriterT $ witherM (\obj -> MaybeT (lift $ liftM is $ elevate $ runMortal obj f)+      >>= \(x, obj') -> lift (writer (obj', Endo (x:)))) t+  elevate (put t')+  return (e [])+  where+    is (Left ()) = Nothing+    is (Right a) = Just a++type Variable s = forall m. Monad m => Object (StateT s m) m++-- | A mutable variable.+variable :: s -> Variable s+variable s = Object $ \m -> liftM (fmap variable) $ runStateT m s++moore :: Applicative f => (a -> r -> f r) -> r -> Object (PushPull a r) f+moore f = go where+  go r = Object $ \pp -> case pp of+    Push a c -> fmap (\z -> (c, z `seq` go z)) (f a r)+    Pull cont -> pure (cont r, go r)+{-# INLINE moore #-}++foldPP :: Applicative f => (a -> r -> r) -> r -> Object (PushPull a r) f+foldPP f = go where+  go r = Object $ \pp -> case pp of+    Push a c -> let z = f a r in pure (c, z `seq` go z)+    Pull cont -> pure (cont r, go r)+{-# INLINE foldPP #-}
+ src/Control/Object/Mortal.hs view
@@ -0,0 +1,62 @@+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE Rank2Types #-}+module Control.Object.Mortal (+    Mortal(..),+    mortal,+    mortal_,+    runMortal,+    immortal,+    reincarnation+    ) where++import Control.Object.Object+import Control.Applicative+import Control.Monad.Trans.Either+import Control.Monad+import Control.Monad.Trans.Class+import Unsafe.Coerce++-- | Object with a final result.+--+-- @Object f g ≡ Mortal f g Void@+--+newtype Mortal f g a = Mortal { unMortal :: Object f (EitherT a g) }++instance (Functor m, Monad m) => Functor (Mortal f m) where+  fmap f (Mortal obj) = Mortal (obj @>>^ bimapEitherT f id)+  {-# INLINE fmap #-}++instance (Functor m, Monad m) => Applicative (Mortal f m) where+  pure = return+  {-# INLINE pure #-}+  (<*>) = ap+  {-# INLINE (<*>) #-}++instance Monad m => Monad (Mortal f m) where+  return a = mortal $ const $ left a+  {-# INLINE return #-}+  m >>= k = mortal $ \f -> lift (runMortal m f) >>= \r -> case r of+    Left a -> EitherT $ runMortal (k a) f+    Right (x, m') -> return (x, m' >>= k)++mortal :: (forall x. f x -> EitherT a m (x, Mortal f m a)) -> Mortal f m a+mortal f = unsafeCoerce f+{-# INLINE mortal #-}++runMortal :: Mortal f m a -> f x -> m (Either a (x, Mortal f m a))+runMortal = unsafeCoerce+{-# INLINE runMortal #-}++-- | Restricted 'Mortal' constuctor, which can be applied to 'transit', 'fromFoldable' without ambiguousness.+mortal_ :: Object f (EitherT () g) -> Mortal f g ()+mortal_ = Mortal+{-# INLINE mortal_ #-}++immortal :: Monad m => Object f m -> Mortal f m x+immortal obj = mortal $ \f -> EitherT $ runObject obj f >>= \(a, obj') -> return $ Right (a, immortal obj')++reincarnation :: Monad m => (a -> Mortal f m a) -> a -> Object f m+reincarnation g a0 = go (g a0) where+  go m = Object $ \f -> runMortal m f >>= \r -> case r of+    Left a -> runObject (go (g a)) f+    Right (a, m') -> return (a, go m')
+ src/Control/Object/Object.hs view
@@ -0,0 +1,170 @@+{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE Rank2Types, CPP, TypeOperators #-}+#if __GLASGOW_HASKELL__ >= 707+{-# LANGUAGE DeriveDataTypeable #-}+#endif+module Control.Object.Object where+import Data.Functor.Day+import Data.Functor.Coproduct+import Control.Monad+import Control.Monad.Free+import Control.Monad.Operational.Mini+import qualified Control.Monad.Trans.Free as T+import qualified Control.Monad.Trans.Operational.Mini as T+import Control.Monad.Trans.State.Strict+import Data.OpenUnion1.Clean+import Data.Typeable+import Control.Applicative++-- | The type @Object f g@ represents objects which can handle messages @f@, perform actions in the environment @g@.+-- It can be thought of as an automaton that converts effects.+-- 'Object's can be composed just like functions using '@>>@'; the identity element is 'echo'.+-- Objects are morphisms of the category of functors+newtype Object f g = Object { runObject :: forall x. f x -> g (x, Object f g) }+#if __GLASGOW_HASKELL__ >= 707+  deriving (Typeable)+#else+instance (Typeable1 f, Typeable1 g) => Typeable (Object f g) where+  typeOf t = mkTyConApp objectTyCon [typeOf1 (f t), typeOf1 (g t)] where+    f :: Object f g -> f a+    f = undefined+    g :: Object f g -> g a+    g = undefined++objectTyCon :: TyCon+#if __GLASGOW_HASKELL__ < 704+objectTyCon = mkTyCon "Control.Object.Object"+#else+objectTyCon = mkTyCon3 "objective" "Control.Object" "Object"+#endif+{-# NOINLINE objectTyCon #-}+#endif++-- | An alias for 'runObject'.+(@-) :: Object f g -> f x -> g (x, Object f g)+(@-) = runObject+{-# INLINE (@-) #-}+infixr 3 @-++-- | The identity object+echo :: Functor f => Object f f+echo = Object (fmap (\x -> (x, echo)))++-- | Lift a natural transformation into an object.+liftO :: Functor g => (forall x. f x -> g x) -> Object f g+liftO f = go where go = Object $ fmap (\x -> (x, go)) . f+{-# INLINE liftO #-}++-- | The unwrapped analog of 'stateful'+--     @unfoldO runObject = id@+--     @unfoldO runSequential = sequential@+--     @unfoldO iterObject = iterable@+unfoldO :: Functor g => (forall a. r -> f a -> g (a, r)) -> r -> Object f g+unfoldO h = go where go r = Object $ fmap (fmap go) . h r+{-# INLINE unfoldO #-}++unfoldOM :: Monad m => (forall a. r -> f a -> m (a, r)) -> r -> Object f m+unfoldOM h = go where go r = Object $ liftM (fmap go) . h r+{-# INLINE unfoldOM #-}++-- | Build a stateful object.+--+-- @stateful t s = t ^>>@ variable s@+stateful :: Monad m => (forall a. f a -> StateT s m a) -> s -> Object f m+stateful h = go where+  go s = Object $ liftM (\(a, s') -> (a, go s')) . flip runStateT s . h+{-# INLINE stateful #-}++-- | Object-object composition+(@>>@) :: Functor h => Object f g -> Object g h -> Object f h+Object m @>>@ Object n = Object $ fmap (\((x, m'), n') -> (x, m' @>>@ n')) . n . m+infixr 1 @>>@++-- | Reversed '(@>>@)'+(@<<@) :: Functor h => Object g h -> Object f g -> Object f h+(@<<@) = flip (@>>@)+{-# INLINE (@<<@) #-}+infixl 1 @<<@+++-- | Object-function composition+(@>>^) :: Functor h => Object f g -> (forall x. g x -> h x) -> Object f h+m0 @>>^ g = go m0 where go (Object m) = Object $ fmap (fmap go) . g . m+infixr 1 @>>^++-- | Function-object composition+(^>>@) :: Functor h => (forall x. f x -> g x) -> Object g h -> Object f h+f ^>>@ m0 = go m0 where go (Object m) = Object $ fmap (fmap go) . m . f+infixr 1 ^>>@++-- | Parallel composition+(@**@) :: Applicative m => Object f m -> Object g m -> Object (Day f g) m+a @**@ b = Object $ \(Day f g r) -> (\(x, a') (y, b') -> (r x y, a' @**@ b')) <$> runObject a f <*> runObject b g+infixr 3 @**@++-- | Objective fanin+(@||@) :: Functor m => Object f m -> Object g m -> Object (Coproduct f g) m+a @||@ b = Object $ \(Coproduct r) -> case r of+  Left f -> fmap (fmap (@||@b)) (runObject a f)+  Right g -> fmap (fmap (a@||@)) (runObject b g)+infixr 2 @||@++-- | An object that won't accept any messages.+loner :: Functor f => Object Nil f+loner = liftO exhaust++-- | Extend an object by another independent object.+(@|>@) :: Functor g => Object f g -> Object (Union s) g -> Object (f |> Union s) g+p @|>@ q = Object $ fmap (fmap (@|>@q)) . runObject p ||> fmap (fmap (p @|>@)) . runObject q+infixr 3 @|>@++-- | Build a stateful object, sharing out the state.+sharing :: Monad m => (forall a. f a -> StateT s m a) -> s -> Object (State s |> f |> Nil) m+sharing m = go where+  go s = Object $ \k -> liftM (fmap go) $ ($k)+    $ (\n -> return $ runState n s)+    ||> (\e -> runStateT (m e) s)+    ||> exhaust+{-# INLINE sharing #-}++(@!) :: Monad m => Object e m -> ReifiedProgram e a -> m (a, Object e m)+obj @! Return a = return (a, obj)+obj @! (e :>>= cont) = runObject obj e >>= \(a, obj') -> obj' @! cont a+infixr 3 @!++(@!!) :: Monad m => Object e m -> T.ReifiedProgramT e m a -> m (a, Object e m)+obj @!! T.Return a = return (a, obj)+obj @!! T.Lift m cont = m >>= (obj @!!) . cont+obj @!! (e T.:>>= cont) = runObject obj e >>= \(a, obj') -> obj' @!! cont a+infixr 3 @!!++iterObject :: Monad m => Object f m -> Free f a -> m (a, Object f m)+iterObject obj (Pure a) = return (a, obj)+iterObject obj (Free f) = runObject obj f >>= \(cont, obj') -> iterObject obj' cont++iterTObject :: Monad m => Object f m -> T.FreeT f m a -> m (a, Object f m)+iterTObject obj m = T.runFreeT m >>= \r -> case r of+  T.Pure a -> return (a, obj)+  T.Free f -> runObject obj f >>= \(cont, obj') -> iterTObject obj' cont++-- | Let object handle 'ReifiedProgram'.+sequential :: Monad m => Object e m -> Object (ReifiedProgram e) m+sequential = unfoldOM (@!)++-- | Let object handle 'ReifiedProgramT'.+sequentialT :: Monad m => Object e m -> Object (T.ReifiedProgramT e m) m+sequentialT = unfoldOM (@!!)++iterative :: Monad m => Object f m -> Object (Free f) m+iterative = unfoldOM iterObject++iterativeT :: Monad m => Object f m -> Object (T.FreeT f m) m+iterativeT = unfoldOM iterTObject++-- | Change the workspace of the object.+transObject :: Functor g => (forall x. f x -> g x) -> Object e f -> Object e g+transObject f = (@>>^f)++-- | Apply a function to methods coming into an object.+adaptObject :: Functor m => (forall x. g x -> f x) -> Object f m -> Object g m+adaptObject f = (f^>>@)
+ src/Control/Object/Process.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE Trustworthy #-}+module Control.Object.Process where+import Control.Object.Object+import Control.Arrow as A+import qualified Control.Category as C+import Data.Profunctor+import Control.Applicative+import Control.Monad+import Data.Monoid+import Data.Functor.Request++-- | An object which is specialized to be a Mealy machine+newtype Process m a b = Process { unProcess :: Object (Request a b) m }++-- | @_Process :: Iso' (Object (Request a b) m) (Process m a b)@+_Process :: (Profunctor p, Functor f) => p (Process m a b) (f (Process m a b)) -> p (Object (Request a b) m) (f (Object (Request a b) m))+_Process = dimap Process (fmap unProcess)++instance Functor f => Functor (Process f a) where+  fmap f (Process o0) = Process $ go o0 where+    go o = Object $ \(Request a cont) -> fmap (cont *** go) $ runObject o (Request a f)++instance Applicative f => Applicative (Process f a) where+  pure a = Process go where+    go = Object $ \(Request _ cont) -> pure (cont a, go)+  Process f0 <*> Process a0 = Process $ go f0 a0 where+    go mf ma = Object $ \(Request a cont) -> (\(f, mf') (x, ma') -> (cont (f x), go mf' ma'))+      <$> runObject mf (Request a id)+      <*> runObject ma (Request a id)++instance (Applicative f, Monoid b) => Monoid (Process f a b) where+  mempty = pure mempty+  mappend = liftA2 mappend++instance Monad m => C.Category (Process m) where+  id = arr id+  Process g0 . Process f0 = Process $ go f0 g0 where+    go f g = Object $ \(Request a cont) -> runObject f (Request a id)+      >>= \(b, f') -> liftM (\(c, g') -> (cont c, go f' g')) $ runObject g (Request b id)++instance Monad m => Arrow (Process m) where+  arr f = Process go where+    go = Object $ \(Request a cont) -> return (cont (f a), go)+  first (Process f0) = Process $ go f0 where+    go f = Object $ \(Request (a, c) cont) -> liftM (\(b, f') -> (cont (b, c), go f')) $ runObject f (Request a id)+  second (Process f0) = Process $ go f0 where+    go f = Object $ \(Request (a, c) cont) -> liftM (\(d, f') -> (cont (a, d), go f')) $ runObject f (Request c id)++instance Monad m => ArrowChoice (Process m) where+  left (Process f0) = Process $ go f0 where+    go f = Object $ \(Request e cont) -> case e of+      Left a -> liftM (\(b, f') -> (cont (Left b), go f')) $ runObject f (Request a id)+      Right c -> return (cont (Right c), go f)+  right (Process f0) = Process $ go f0 where+    go f = Object $ \(Request e cont) -> case e of+      Right a -> liftM (\(b, f') -> (cont (Right b), go f')) $ runObject f (Request a id)+      Left c -> return (cont (Left c), go f)++instance Monad m => Profunctor (Process m) where+  dimap f g (Process f0) = Process (go f0) where+    go m = Object $ \(Request a cont) -> liftM (\(b, m') -> (cont (g b), go m')) $ runObject m (Request (f a) id)+  {-# INLINE dimap #-}++instance Monad m => Strong (Process m) where+  first' = first+  {-# INLINE first' #-}+  second' = second+  {-# INLINE second' #-}++instance Monad m => Choice (Process m) where+  left' = A.left+  {-# INLINE left' #-}+  right' = A.right+  {-# INLINE right' #-}++instance (Applicative m, Num o) => Num (Process m i o) where+  (+) = liftA2 (+)+  {-# INLINE (+) #-}+  (-) = liftA2 (-)+  {-# INLINE (-) #-}+  (*) = liftA2 (*)+  {-# INLINE (*) #-}+  abs = fmap abs+  {-# INLINE abs #-}+  signum = fmap signum+  {-# INLINE signum #-}+  fromInteger = pure . fromInteger+  {-# INLINE fromInteger #-}++instance (Applicative m, Fractional o) => Fractional (Process m i o) where+  (/) = liftA2 (/)+  {-# INLINE (/) #-}+  recip = fmap recip+  fromRational = pure . fromRational
+ src/Control/Object/Stream.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE Trustworthy #-}+module Control.Object.Stream where++import Data.Functor.Rep+import Data.Functor.Adjunction+import Control.Object.Object+import Data.Foldable as F+import Control.Applicative+import Data.Functor.Request+import Control.Monad+import Control.Monad.Trans.Either+import Control.Object.Mortal++-- | For every adjunction f ⊣ g, we can "connect" @Object g m@ and @Object f m@ permanently.+($$) :: (Monad m, Adjunction f g) => Object g m -> Object f m -> m x+a $$ b = do+  (x, a') <- runObject a askRep+  ((), b') <- runObject b (unit () `index` x)+  a' $$ b'+infix 1 $$++($?$) :: (Monad m, Adjunction f g) => Object g (EitherT a m) -> Object f (EitherT a m) -> m a+a $?$ b = liftM (either id id) $ runEitherT (a $$ b)+{-# INLINE ($?$) #-}++(!$$!) :: (Monad m, Adjunction f g) => Mortal g m a -> Mortal f m a -> m a+Mortal a !$$! Mortal b = a $?$ b+{-# INLINE (!$$!) #-}++-- | Create a source from a 'Foldable' container.+fromFoldable :: (Foldable t, Alternative m, Representable f) => t (Rep f) -> Object f m+fromFoldable = F.foldr go $ Object $ const empty where+  go x m = Object $ \cont -> pure (index cont x, m)++mapL :: (Adjunction f g, Adjunction f' g', Functor m) => (Rep g' -> Rep g) -> Object f m -> Object f' m+mapL t = (^>>@) $ rightAdjunct $ \x -> tabulate (index (unit x) . t)++mapR :: (Representable f, Representable g, Functor m) => (Rep f -> Rep g) -> Object f m -> Object g m+mapR t = (^>>@) $ \f -> tabulate (index f . t)++filterL :: (Adjunction f g, Applicative m) => (Rep g -> Bool) -> Object f m -> Object f m+filterL p obj = Object $ \f -> if counit (tabulate p <$ f)+  then fmap (filterL p) `fmap` runObject obj f+  else pure (extractL f, filterL p obj)++filterR :: (Representable f, Monad m) => (Rep f -> Bool) -> Object f m -> Object f m+filterR p obj = Object $ \f -> go f obj where+  go f o = do+    (x, o') <- runObject o askRep+    if p x+      then return (index f x, filterR p o')+      else go f o'++-- | Attack a rank-1 Mealy machine to a source.+($$@) :: (Representable f, Representable g, Monad m) => Object f m -> Object (Request (Rep f) (Rep g)) m -> Object g m+obj $$@ pro = Object $ \g -> do+  (x, obj') <- runObject obj askRep+  (a, pro') <- runObject pro $ Request x (index g)+  return (a, obj' $$@ pro')++-- | Attach a rank-1 Mealy machine into a sink.+(@$$) :: (Adjunction f g, Adjunction f' g', Monad m) => Object (Request (Rep g') (Rep g)) m -> Object f m -> Object f' m+pro @$$ obj = Object $ \f' -> do+  let (a, f_) = splitL f'+  (x, pro') <- runObject pro $ Request (counit (askRep <$ f_)) id+  ((), obj') <- runObject obj $ unit () `index` x+  return (a, pro' @$$ obj')
src/Data/Functor/PushPull.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE Trustworthy #-}
 {-# LANGUAGE DeriveFunctor, DeriveDataTypeable, ConstraintKinds, FlexibleContexts, DataKinds, TypeFamilies, TypeOperators #-}
 -----------------------------------------------------------------------------
 -- |
src/Data/Functor/Request.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE Trustworthy #-}
 {-# LANGUAGE DeriveFunctor, DeriveDataTypeable, ConstraintKinds, FlexibleContexts, TypeOperators, DataKinds, TypeFamilies #-}
 -----------------------------------------------------------------------------
 -- |