objective 1.0.5 → 1.3
raw patch · 11 files changed
Files
- .travis.yml +0/−56
- CHANGELOG.md +24/−0
- LICENSE +30/−30
- README.md +46/−0
- Setup.hs +2/−2
- objective.cabal +8/−21
- src/Control/Object.hs +0/−1
- src/Control/Object/Instance.hs +35/−52
- src/Control/Object/Mortal.hs +25/−43
- src/Control/Object/Object.hs +22/−77
- src/Data/Functor/Request.hs +0/−94
− .travis.yml
@@ -1,56 +0,0 @@-# NB: don't set `language: haskell` here - -# See also https://github.com/hvr/multi-ghc-travis for more information - -# The following lines enable several GHC versions and/or HP versions -# to be tested; often it's enough to test only against the last -# release of a major GHC version. Setting HPVER implictly sets -# GHCVER. Omit lines with versions you don't need/want testing for. -env: - - CABALVER=1.18 GHCVER=7.6.3 - - CABALVER=1.18 GHCVER=7.8.4 - - CABALVER=1.22 GHCVER=7.10.1 - -# Note: the distinction between `before_install` and `install` is not -# important. -before_install: - - travis_retry sudo add-apt-repository -y ppa:hvr/ghc - - travis_retry sudo apt-get update - - travis_retry sudo apt-get install cabal-install-$CABALVER ghc-$GHCVER - - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH - -install: - - cabal --version - - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]" - - travis_retry cabal update - - cabal install --only-dependencies --enable-tests --enable-benchmarks - -# Here starts the actual work to be performed for the package under -# test; any command which exits with a non-zero exit code causes the -# build to fail. -script: - - if [ -f configure.ac ]; then autoreconf -i; fi - # -v2 provides useful information for debugging - - cabal configure --enable-tests --enable-benchmarks -v2 - - # this builds all libraries and executables - # (including tests/benchmarks) - - cabal build - - - cabal test - - cabal check - - # tests that a source-distribution can be generated - - cabal sdist - - # check that the generated source-distribution can be built & installed - - export SRC_TGZ=$(cabal info . | awk '{print $2 ".tar.gz";exit}') ; - cd dist/; - if [ -f "$SRC_TGZ" ]; then - cabal install --force-reinstalls "$SRC_TGZ"; - else - echo "expected '$SRC_TGZ' not found"; - exit 1; - fi - -# EOF
CHANGELOG.md view
@@ -1,3 +1,27 @@+1.3+----+* Supported GHC 9.0+* Removed `unfoldOM`+* Removed `apprisesOf`+* Removed `withBuilder`+* Trimmed unnecessary dependencies++1.2+----++* Removed `iterObject` and `iterative`+* Removed `Data.Functor.Request`++1.1.2+----++* Removed `either` dependency++1.1+----+* Removed `HProfunctor`, `(..-)`, `invokeOnSTM`, `newSTM`, `snapshot`+* Added `(?-)`+ 1.0.5 ---- * Added `filterO` and `filteredO`
LICENSE view
@@ -1,30 +1,30 @@-Copyright (c) 2014, Fumiaki Kinoshita - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of Fumiaki Kinoshita nor the names of other - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Copyright (c) 2014, Fumiaki Kinoshita++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Fumiaki Kinoshita nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,46 @@+objective+====++[](https://hackage.haskell.org/package/objective) [](http://travis-ci.org/fumieval/objective)++Paper: https://fumieval.github.io/papers/en/2015-Haskell-objects.html++This package provides composable objects and instances.++Introduction+----++The primal construct, `Object`, models _object-oriented_ objects. `Object f g` represents an object.++```haskell+newtype Object f g = Object { runObject :: forall x. f x -> g (x, Object f g) }+```++An object interprets a message `f a` and returns the result `a` and the next object `Object f g`, on `g`.++```haskell+data Counter a where+ Increment :: Counter ()+ Print :: Counter Int++counter :: Int -> Object Counter IO+counter n = Object $ \case+ Increment -> return ((), counter (n + 1))+ Print -> print n >> return (n, counter n)+```++`new :: Object f g -> IO (Instance f g)` creates an instance of an object.++`(.-) :: (MonadIO m, MonadMask m) => Instance f m -> f a -> m a` sends a message to an instance. This can be used to handle instances in the typical OOP fashion.++```haskell+> i <- new (counter 0)+> i .- Increment+> i .- Print+1+> i .- Increment+> i .- Print+2+```++Interestingly, `Object (Skeleton t) m` and `Object t m` are isomorphic (`Skeleton` is an operational monad). `cascading` lets objects to handle an operational monad.
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple -main = defaultMain +import Distribution.Simple+main = defaultMain
objective.cabal view
@@ -1,20 +1,20 @@+cabal-version: 2.4 name: objective-version: 1.0.5+version: 1.3 synopsis: Composable objects description: Composable objects homepage: https://github.com/fumieval/objective bug-reports: http://github.com/fumieval/objective/issues-license: BSD3+license: BSD-3-Clause license-file: LICENSE author: Fumiaki Kinoshita maintainer: Fumiaki Kinoshita <fumiexcel@gmail.com>-copyright: Copyright (c) 2014 Fumiaki Kinoshita+copyright: Copyright (c) 2014-2021 Fumiaki Kinoshita category: Control build-type: Simple extra-source-files: CHANGELOG.md- .travis.yml-cabal-version: >=1.10+ README.md source-repository head type: git@@ -26,25 +26,12 @@ , Control.Object.Object , Control.Object.Instance , Control.Object.Mortal- , Data.Functor.Request other-extensions: MultiParamTypeClasses, KindSignatures, TypeFamilies- build-depends: base >=4.6 && <5- , either >= 4.3 && <4.5+ build-depends: base >=4.9 && <5 , exceptions >= 0.8- , containers >= 0.5.0.0 && <0.6- , unordered-containers >= 0.2.0.0 && <0.3 , transformers >= 0.3 && <0.6- , transformers-compat- , free >= 4 && <5- , hashable- , mtl- , profunctors- , void- , witherable >= 0.1.3- , stm- , monad-stm+ , witherable ^>= 0.4 , monad-skeleton >= 0.1.1 && <0.3- , template-haskell- ghc-options: -Wall+ ghc-options: -Wall -Wcompat hs-source-dirs: src default-language: Haskell2010
src/Control/Object.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE Safe #-} ----------------------------------------------------------------------------- -- | -- Module : Control.Object
src/Control/Object/Instance.hs view
@@ -1,5 +1,4 @@-{-# LANGUAGE Safe #-}-{-# LANGUAGE GADTs, Rank2Types #-}+{-# LANGUAGE GADTs, Rank2Types, LambdaCase #-} ----------------------------------------------------------------------------- -- | -- Module : Control.Object.Instance@@ -13,61 +12,40 @@ ----------------------------------------------------------------------------- module Control.Object.Instance ( -- * Instantiation- Instance(..)+ Instance , new , newSettle- , newSTM -- * Invocation+ , invokeOnUsing , invokeOn- , invokeOnSTM , (.-) , (..-)- , snapshot+ , (?-) ) where-import Control.Concurrent.STM.TMVar-import Control.Monad.STM+import Control.Concurrent+import Control.Exception (evaluate) import Control.Object.Object import Control.Monad.IO.Class-import Control.Monad.STM.Class-import Control.Monad-import Control.Monad.Catch (MonadMask, bracketOnError)+import Control.Monad.Catch+import Control.Monad.Skeleton --- | TMVar-based instance-data Instance f g where- InstRef :: (forall x. e x -> f x) -> (forall x. g x -> h x) -> TMVar (Object f g) -> Instance e h+type Instance f g = MVar (Object f g) -instance HProfunctor Instance where- f ^>>@ InstRef l r v = InstRef (l . f) r v- {-# INLINE (^>>@) #-}- InstRef l r v @>>^ f = InstRef l (f . r) v- {-# INLINE (@>>^) #-}+invokeOnUsing :: (MonadIO m, MonadMask m)+ => (Object f g -> t a -> g (a, Object f g))+ -> (forall x. g x -> m x) -> Instance f g -> t a -> m a+invokeOnUsing run m v f = mask $ \restore -> do+ obj <- liftIO $ takeMVar v+ (a, obj') <- restore (m (run obj f) >>= liftIO . evaluate) `onException` liftIO (putMVar v obj)+ liftIO $ putMVar v obj'+ return a -- | Invoke a method with an explicit landing function.+-- In case of exception, the original object will be set. invokeOn :: (MonadIO m, MonadMask m) => (forall x. g x -> m x) -> Instance f g -> f a -> m a-invokeOn m (InstRef t l v) f = bracketOnError- (liftIO $ atomically $ takeTMVar v)- (\obj -> liftIO $ atomically $ do- _ <- tryTakeTMVar v- putTMVar v obj)- (\obj -> do- (a, obj') <- m $ l $ runObject obj (t f)- liftIO $ atomically $ putTMVar v obj'- return a)---- | Invoke a method with an explicit landing function.-invokeOnSTM :: (forall x. g x -> STM x) -> Instance f g -> f a -> STM a-invokeOnSTM m (InstRef t l v) f = do- obj <- takeTMVar v- (a, obj') <- m $ l $ runObject obj (t f)- putTMVar v obj'- return a---- | Invoke a method, atomically.-(..-) :: MonadSTM m => Instance f STM -> f a -> m a-(..-) i = liftSTM . invokeOnSTM id i-{-# INLINE (..-) #-}-infixr 3 ..-+invokeOn = invokeOnUsing (\o f -> runObject o f)+{-# INLINE invokeOn #-} -- | Invoke a method. (.-) :: (MonadIO m, MonadMask m) => Instance f m -> f a -> m a@@ -75,22 +53,27 @@ {-# INLINE (.-) #-} infixr 3 .- --- | Take a snapshot of an instance.-snapshot :: (MonadSTM m, Functor g) => Instance f g -> m (Object f g)-snapshot (InstRef f g v) = liftSTM $ go `fmap` readTMVar v- where go (Object m) = Object $ fmap (fmap go) . g . m . f+(..-) :: (MonadIO m, MonadMask m)+ => Instance t m -> Skeleton t a -> m a+(..-) = invokeOnUsing cascadeObject id+{-# INLINE (..-) #-}+infixr 3 ..- +-- | Try to invoke a method. If the instance is unavailable, it returns Nothing.+(?-) :: (MonadIO m, MonadMask m) => Instance f m -> f a -> m (Maybe a)+v ?- f = mask $ \restore -> liftIO (tryTakeMVar v) >>= \case+ Just obj -> do+ (a, obj') <- restore (runObject obj f >>= liftIO . evaluate) `onException` liftIO (putMVar v obj)+ liftIO $ putMVar v obj'+ return (Just a)+ Nothing -> return Nothing+ -- | Create a new instance. This can be used inside 'unsafePerformIO' to create top-level instances. new :: MonadIO m => Object f g -> m (Instance f g)-new = liftIO . liftM (InstRef id id) . newTMVarIO+new = liftIO . newMVar {-# INLINE new #-} -- | Create a new instance, having it sitting on the current environment. newSettle :: MonadIO m => Object f m -> m (Instance f m) newSettle = new {-# INLINE newSettle #-}---- | Create a new instance.-newSTM :: MonadSTM m => Object f g -> m (Instance f g)-newSTM = liftSTM . liftM (InstRef id id) . newTMVar-{-# INLINE newSTM #-}
src/Control/Object/Mortal.hs view
@@ -1,5 +1,4 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE Trustworthy #-}+{-# LANGUAGE Safe #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE BangPatterns #-}@@ -20,25 +19,20 @@ mortal_, runMortal, immortal,- apprisesOf, apprises, apprise ) where import Control.Object.Object-#if !MIN_VERSION_base(4,8,0)-import Control.Applicative-#endif-import Control.Monad.Trans.Either+import Control.Monad.Trans.Except import Control.Monad import Control.Monad.Trans.Class import Control.Monad.Trans.State.Strict import Control.Monad.Trans.Writer.Strict+import Data.Bifunctor import Data.Monoid-import Data.Witherable+import Witherable import Data.Tuple (swap)-import Control.Arrow ((***))-import Unsafe.Coerce -- | A 'Mortal' is an object that may die. -- A mortal yields a final result upon death.@@ -47,41 +41,39 @@ -- -- @Object f g ≡ Mortal f g Void@ ---newtype Mortal f g a = Mortal { unMortal :: Object f (EitherT a g) }+newtype Mortal f g a = Mortal { unMortal :: Object f (ExceptT a g) } -instance (Functor m, Monad m) => Functor (Mortal f m) where- fmap f (Mortal obj) = Mortal (obj @>>^ bimapEitherT f id)+instance Monad m => Functor (Mortal f m) where+ fmap f (Mortal obj) = Mortal (obj @>>^ mapExceptT (fmap (first f))) {-# INLINE fmap #-} -instance (Functor m, Monad m) => Applicative (Mortal f m) where- pure = return+instance Monad m => Applicative (Mortal f m) where+ pure a = mortal $ const $ throwE a {-# 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 (runEitherT $ runMortal m f) >>= \r -> case r of+ m >>= k = mortal $ \f -> lift (runExceptT $ runMortal m f) >>= \case Left a -> runMortal (k a) f Right (x, m') -> return (x, m' >>= k) instance MonadTrans (Mortal f) where- lift m = mortal $ const $ EitherT $ liftM Left m+ lift m = mortal $ const $ ExceptT $ fmap Left m {-# INLINE lift #-} -- | Construct a mortal in a 'Object' construction manner.-mortal :: Monad m => (forall x. f x -> EitherT a m (x, Mortal f m a)) -> Mortal f m a-mortal f = unsafeCoerce f `asTypeOf` Mortal (Object (fmap (fmap unMortal) . f))+mortal :: Monad m => (forall x. f x -> ExceptT a m (x, Mortal f m a)) -> Mortal f m a+mortal f = Mortal (Object (fmap (fmap unMortal) . f)) {-# INLINE mortal #-} -- | Send a message to a mortal.-runMortal :: Monad m => Mortal f m a -> f x -> EitherT a m (x, Mortal f m a)-runMortal = unsafeCoerce `asTypeOf` ((fmap (fmap Mortal) . ) . runObject . unMortal)+runMortal :: Monad m => Mortal f m a -> f x -> ExceptT a m (x, Mortal f m a)+runMortal m f = fmap Mortal <$> runObject (unMortal m) f {-# INLINE runMortal #-} --- | Restricted 'Mortal' constuctor which can be applied to 'transit', 'fromFoldable' without ambiguousness.-mortal_ :: Object f (EitherT () g) -> Mortal f g ()+-- | A smart constructor of 'Mortal' where the result type is restricted to ()+mortal_ :: Object f (ExceptT () g) -> Mortal f g () mortal_ = Mortal {-# INLINE mortal_ #-} @@ -90,26 +82,16 @@ immortal obj = Mortal (obj @>>^ lift) {-# INLINE immortal #-} --- | Send a message to mortals through a filter.-apprisesOf :: Monad m- => FilterLike' (WriterT r m) s (Mortal f m b)- -> f a -> (a -> r) -> (b -> r) -> StateT s m r-apprisesOf l f p q = StateT $ \t -> liftM swap $ runWriterT $ flip l t- $ \obj -> WriterT $ runEitherT (runMortal obj f) >>= \case- Left r -> return (Nothing, q r)- Right (x, obj') -> return (Just obj', p x)-{-# INLINABLE apprisesOf #-}- -- | Send a message to mortals in a 'Witherable' container.------ @apprises = apprisesOf wither@----apprises :: (Witherable t, Monad m, Applicative m, Monoid r) => f a -> (a -> r) -> (b -> r) -> StateT (t (Mortal f m b)) m r-apprises = apprisesOf wither+apprises :: (Witherable t, Monad m, Monoid r) => f a -> (a -> r) -> (b -> r) -> StateT (t (Mortal f m b)) m r+apprises f p q = StateT $ \t -> fmap swap $ runWriterT $ flip wither t+ $ \obj -> WriterT $ runExceptT (runMortal obj f) >>= \case+ Left r -> return (Nothing, q r)+ Right (x, obj') -> return (Just obj', p x) {-# INLINE apprises #-} -- | Send a message to mortals in a container.-apprise :: (Witherable t, Monad m, Applicative m) => f a -> StateT (t (Mortal f m r)) m ([a], [r])-apprise f = fmap (flip appEndo [] *** flip appEndo [])- $ apprises f (\a -> (Endo (a:), mempty)) (\b -> (mempty, Endo (b:)))+apprise :: (Witherable t, Monad m) => f a -> StateT (t (Mortal f m r)) m ([a], [r])+apprise f = bimap (`appEndo` []) (`appEndo` [])+ <$> apprises f (\a -> (Endo (a:), mempty)) (\b -> (mempty, Endo (b:))) {-# INLINE apprise #-}
src/Control/Object/Object.hs view
@@ -1,12 +1,7 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE Rank2Types, TupleSections, TypeOperators #-}+{-# LANGUAGE RankNTypes, TupleSections, TypeOperators #-} {-# LANGUAGE GADTs #-}-#if __GLASGOW_HASKELL__ >= 707-{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE Safe #-}-#else-{-# LANGUAGE Trustworthy #-}-#endif ----------------------------------------------------------------------------- -- | -- Module : Control.Object.Object@@ -23,18 +18,16 @@ , (@>>@) , (@<<@) , liftO- , HProfunctor(..)+ , (^>>@)+ , (@>>^) , (@||@) -- * Stateful construction , unfoldO- , unfoldOM , stateful , (@~) , variable -- * Method cascading , (@-)- , iterObject- , iterative , cascadeObject , cascading -- * Filtering@@ -46,14 +39,9 @@ , invokes , (@!=) , announce- , withBuilder ) where-import Data.Typeable import Control.Monad.Trans.State.Strict-import Control.Monad.Free-import Control.Monad import Control.Monad.Skeleton-import Data.Traversable as T import Control.Monad.Trans.Writer.Strict import Data.Monoid import Data.Tuple (swap)@@ -68,44 +56,23 @@ -- @runObject obj . fmap f ≡ fmap f . runObject obj@ -- 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 infix alias for 'runObject' (@-) :: Object f g -> f x -> g (x, Object f g)-(@-) = runObject+a @- b = runObject a b {-# INLINE (@-) #-} infixr 3 @- infixr 1 ^>>@ infixr 1 @>>^ --- | Higher-order profunctors-class HProfunctor k where- (^>>@) :: Functor h => (forall x. f x -> g x) -> k g h -> k f h- (@>>^) :: Functor h => k f g -> (forall x. g x -> h x) -> k f h+(^>>@) :: 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+{-# INLINE (^>>@) #-} -instance HProfunctor Object where- m0 @>>^ g = go m0 where go (Object m) = Object $ fmap (fmap go) . g . m- {-# INLINE (@>>^) #-}- f ^>>@ m0 = go m0 where go (Object m) = Object $ fmap (fmap go) . m . f- {-# INLINE (^>>@) #-}+(@>>^) :: 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+{-# INLINE (@>>^) #-} -- | The trivial object echo :: Functor f => Object f f@@ -129,7 +96,7 @@ -- | Combine objects so as to handle a 'Functor.Sum' of interfaces. (@||@) :: Functor h => Object f h -> Object g h -> Object (f `Functor.Sum` g) h-a @||@ b = Object $ \r -> case r of+a @||@ b = Object $ \case Functor.InL f -> fmap (fmap (@||@b)) (runObject a f) Functor.InR g -> fmap (fmap (a@||@)) (runObject b g) @@ -141,11 +108,6 @@ unfoldO h = go where go r = Object $ fmap (fmap go) . h r {-# INLINE unfoldO #-} --- | Same as 'unfoldO' but requires 'Monad' instead-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@@@ -162,16 +124,6 @@ {-# INLINE (@~) #-} infix 1 @~ --- | Cascading-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---- | Objects can consume free monads. 'cascading' is more preferred.-iterative :: Monad m => Object f m -> Object (Free f) m-iterative = unfoldOM iterObject-{-# INLINE iterative #-}- -- | A mutable variable. -- -- @variable = stateful id@@@ -182,34 +134,31 @@ -- | Pass zero or more messages to an object. cascadeObject :: Monad m => Object t m -> Skeleton t a -> m (a, Object t m)-cascadeObject obj sk = case unbone sk of+cascadeObject obj sk = case debone sk of Return a -> return (a, obj) t :>>= k -> runObject obj t >>= \(a, obj') -> cascadeObject obj' (k a) -- | Add capability to handle multiple messages at once. cascading :: Monad m => Object t m -> Object (Skeleton t) m-cascading = unfoldOM cascadeObject+cascading = unfoldO cascadeObject {-# INLINE cascading #-} -- | Send a message to an object through a lens. invokesOf :: Monad m => ((Object t m -> WriterT r m (Object t m)) -> s -> WriterT r m s) -> t a -> (a -> r) -> StateT s m r-invokesOf t f c = StateT $ liftM swap . runWriterT+invokesOf t f c = StateT $ fmap swap . runWriterT . t (\obj -> WriterT $ runObject obj f >>= \(x, obj') -> return (obj', c x)) {-# INLINABLE invokesOf #-} -invokes :: (T.Traversable t, Monad m, Monoid r)+invokes :: (Traversable t, Monad m, Monoid r) => f a -> (a -> r) -> StateT (t (Object f m)) m r-invokes = invokesOf T.mapM+invokes = invokesOf traverse {-# INLINE invokes #-} -- | Send a message to objects in a traversable container.------ @announce = withBuilder . invokesOf traverse@----announce :: (T.Traversable t, Monad m) => f a -> StateT (t (Object f m)) m [a]-announce f = withBuilderM (invokes f)+announce :: (Traversable t, Monad m) => f a -> StateT (t (Object f m)) m [a]+announce f = withListBuilder (invokes f) {-# INLINABLE announce #-} -- | A method invocation operator on 'StateT'.@@ -219,13 +168,9 @@ l @!= f = invokesOf l f id {-# INLINE (@!=) #-} -withBuilder :: Functor f => ((a -> Endo [a]) -> f (Endo [a])) -> f [a]-withBuilder f = fmap (flip appEndo []) (f (Endo . (:)))-{-# INLINABLE withBuilder #-}--withBuilderM :: Monad f => ((a -> Endo [a]) -> f (Endo [a])) -> f [a]-withBuilderM f = liftM (flip appEndo []) (f (Endo . (:)))-{-# INLINABLE withBuilderM #-}+withListBuilder :: Functor f => ((a -> Endo [a]) -> f (Endo [a])) -> f [a]+withListBuilder f = fmap (flip appEndo []) (f (Endo . (:)))+{-# INLINABLE withListBuilder #-} data Fallible t a where Fallible :: t a -> Fallible t (Maybe a)
− src/Data/Functor/Request.hs
@@ -1,94 +0,0 @@-{-# LANGUAGE Safe #-}-{-# LANGUAGE CPP, DeriveFunctor, DeriveDataTypeable, ConstraintKinds, FlexibleContexts, TypeOperators, DataKinds, TypeFamilies #-}--------------------------------------------------------------------------------- |--- Module : Data.Functor.Request--- Copyright : (c) Fumiaki Kinoshita 2015--- License : BSD3------ Maintainer : Fumiaki Kinoshita <fumiexcel@gmail.com>--- Stability : experimental--- Portability : non-portable----------------------------------------------------------------------------------module Data.Functor.Request where-import Data.Typeable-#if !MIN_VERSION_base(4,8,0)-import Data.Monoid-#endif-import Control.Applicative-import Data.Profunctor-import Control.Object.Object-import qualified Data.HashMap.Strict as HM-import Data.Hashable-import Control.Arrow---- | @'Request' a b@ is the type of a request that sends @a@ to receive @b@.-data Request a b r = Request a (b -> r) deriving (Functor, Typeable)---- | Apply a function to the body of 'Request'-mapRequest :: (a -> a') -> Request a b r -> Request a' b r-mapRequest f (Request a br) = Request (f a) br-{-# INLINE mapRequest #-}--instance Profunctor (Request a) where- dimap f g (Request a br) = Request a (dimap f g br)- {-# INLINE dimap #-}--instance Monoid a => Applicative (Request a b) where- pure a = Request mempty (const a)- {-# INLINE pure #-}- Request a c <*> Request b d = Request (mappend a b) (c <*> d)- {-# INLINE (<*>) #-}---- | Create a 'Request'.-request :: a -> Request a b b-request a = Request a id-{-# INLINE request #-}---- | Handle a 'Request', smashing the continuation.-accept :: Functor m => (a -> m b) -> Request a b r -> m r-accept f = \(Request a cont) -> cont <$> f a-{-# INLINE accept #-}---- | Add a step as a mealy machine-mealy :: Functor m => (a -> m (b, Object (Request a b) m)) -> Object (Request a b) m-mealy f = Object $ \(Request a cont) -> first cont <$> f a-{-# INLINE mealy #-}---- | The flyweight object-flyweight :: (Applicative m, Eq k, Hashable k) => (k -> m a) -> Object (Request k a) m-flyweight f = go HM.empty where- go m = mealy $ \k -> case HM.lookup k m of- Just a -> pure (a, go m)- Nothing -> (\a -> (a, go $ HM.insert k a m)) <$> f k-{-# INLINE flyweight #-}---- | Compose mealy machines-(>~~>) :: Monad m => Object (Request a b) m -> Object (Request b c) m -> Object (Request a c) m-p >~~> q = Object $ \(Request a cont) -> do- (b, p') <- runObject p (Request a id)- (r, q') <- runObject q (Request b cont)- return (r, p' >~~> q')--accumulator :: Applicative m => (b -> a -> b) -> b -> Object (Request a b) m-accumulator f = go where- go b = mealy $ \a -> pure (b, go (f b a))-{-# INLINE accumulator #-}---- | Create a mealy machine from a time-varying action.------ @ animate f ≡ accumulator (+) 0 >~~> liftO (accept f)@----animate :: (Applicative m, Num t) => (t -> m a) -> Object (Request t a) m-animate f = go 0 where- go t = mealy $ \dt -> flip (,) (go (t + dt)) <$> f t-{-# INLINE animate #-}---- | Like 'animate', but the life is limited.-transit :: (Alternative m, Fractional t, Ord t) => t -> (t -> m a) -> Object (Request t a) m-transit len f = animate go where- go t- | t >= len = empty- | otherwise = f (t / len)-{-# INLINE transit #-}