packages feed

conceit 0.2.2.0 → 0.2.2.1

raw patch · 6 files changed

+275/−271 lines, 6 filessetup-changedPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG view
@@ -1,21 +1,25 @@-0.2.2.0-=======-    - Bumped void and exceptions dependencies.--0.2.1.0-=======-    - Now >> behaves differently from the concurrent *>, and sequences its-      arguments. It makes more sense for the monad. This is what Haxl does as-      well. -    -0.2.0.0-=======-    - Internal changes that remove the necessity for (Show e,Typeable e)-      constraints.-    - Removed async dependency.-    - Many new instances for Conceit.--0.1.1.0-=======--    - Added _Conceit.+0.2.2.1
+=======
+    - Qualified Alt to make it compile with GHC 7.10.
+
+0.2.2.0
+=======
+    - Bumped void and exceptions dependencies.
+
+0.2.1.0
+=======
+    - Now >> behaves differently from the concurrent *>, and sequences its
+      arguments. It makes more sense for the monad. This is what Haxl does as
+      well. 
+    
+0.2.0.0
+=======
+    - Internal changes that remove the necessity for (Show e,Typeable e)
+      constraints.
+    - Removed async dependency.
+    - Many new instances for Conceit.
+
+0.1.1.0
+=======
+
+    - Added _Conceit.
LICENSE view
@@ -1,27 +1,27 @@-Copyright (c) 2014, Daniel Díaz Carrete-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 the {organization} nor the names of its-  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 HOLDER 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, Daniel Díaz Carrete
+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 the {organization} nor the names of its
+  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 HOLDER 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
@@ -1,11 +1,11 @@-conceit-=======--A version of the Concurrently applicative from Simon Marlow's async package,-with the difference that the concurrent computation stops if any of the actions-returns a Left value, not only in the case of exceptions.--The internals have been copied wholesale from Concurrently, with modifications-to support the new behaviour.--Includes a useful Bifunctor instance.+conceit
+=======
+
+A version of the Concurrently applicative from Simon Marlow's async package,
+with the difference that the concurrent computation stops if any of the actions
+returns a Left value, not only in the case of exceptions.
+
+The internals have been copied wholesale from Concurrently, with modifications
+to support the new behaviour.
+
+Includes a useful Bifunctor instance.
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple-main = defaultMain+import Distribution.Simple
+main = defaultMain
conceit.cabal view
@@ -1,36 +1,36 @@-name:          conceit-version:       0.2.2.0-license:       BSD3-license-file:  LICENSE-data-files:    -author:        Daniel Díaz Carrete-maintainer:    diaz_carrete@yahoo.com-category:      Concurrency-build-type:    Simple-cabal-version: >= 1.10-Synopsis:      Concurrent actions that may fail-Description:   A version of the async package's 'Control.Concurrent.Async.Concurrently' for which the actions may fail--Extra-Source-Files:-    README.md-    CHANGELOG--Library-    default-language: Haskell2010-    hs-source-dirs: src-    exposed-modules: -        Control.Concurrent.Conceit-    other-modules: -    build-depends:         -        base >= 4.4 && < 5,-        semigroupoids ==4.*,-        bifunctors >= 4.1 && < 5,-        void >= 0.6 && < 1.0,-        exceptions >= 0.6 && < 1.0,-        mtl >=2.0 && <2.3,-        transformers >=0.2 && < 0.5--Source-repository head-    type:     git-    location: https://github.com/danidiaz/conceit.git-+name:          conceit
+version:       0.2.2.1
+license:       BSD3
+license-file:  LICENSE
+data-files:    
+author:        Daniel Díaz Carrete
+maintainer:    diaz_carrete@yahoo.com
+category:      Concurrency
+build-type:    Simple
+cabal-version: >= 1.10
+Synopsis:      Concurrent actions that may fail
+Description:   A version of the async package's 'Control.Concurrent.Async.Concurrently' for which the actions may fail
+
+Extra-Source-Files:
+    README.md
+    CHANGELOG
+
+Library
+    default-language: Haskell2010
+    hs-source-dirs: src
+    exposed-modules: 
+        Control.Concurrent.Conceit
+    other-modules: 
+    build-depends:         
+        base >= 4.4 && < 5,
+        semigroupoids ==4.*,
+        bifunctors >= 4.1 && < 5,
+        void >= 0.6 && < 1.0,
+        exceptions >= 0.6 && < 1.0,
+        mtl >=2.0 && <2.3,
+        transformers >=0.2 && < 0.5
+
+Source-repository head
+    type:     git
+    location: https://github.com/danidiaz/conceit.git
+
src/Control/Concurrent/Conceit.hs view
@@ -1,174 +1,174 @@-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE CPP #-}--module Control.Concurrent.Conceit ( -          Conceit (..)-        , _Conceit-        , _runConceit-        , conceit-        , mapConceit-    ) where--import Data.Bifunctor-import Data.Monoid-import Data.Typeable-import Data.Traversable-import Data.Void-import Control.Applicative -import Control.Monad-import Control.Monad.IO.Class-import qualified Control.Monad.Catch as Ex-import Control.Exception -import Control.Concurrent-import Data.Functor.Bind-import Data.Functor.Plus--#if MIN_VERSION_mtl(2, 2, 1)-import Control.Monad.Except-#endif--{-| -    'Conceit' is very similar to 'Control.Concurrent.Async.Concurrently' from the-@async@ package, but it has an explicit error type @e@.--   The 'Applicative' instance runs two actions concurrently, waits until-they finish, and combines their results. --   However, if any of the actions fails with @e@ the other action is-   immediately cancelled and the whole computation fails with @e@. --    To put it another way: 'Conceit' behaves like 'Concurrently' for-    successes and like 'race' for errors.  --}-newtype Conceit e a = Conceit { runConceit :: IO (Either e a) } deriving Functor--instance Bifunctor Conceit where-  bimap f g (Conceit x) = Conceit $ liftM (bimap f g) x--instance Applicative (Conceit e) where-  pure = Conceit . pure . pure-  Conceit fs <*> Conceit as =-         Conceit $ fmap (fmap (\(f, a) -> f a)) $ conceit fs as--instance Alternative (Conceit e) where-  empty = Conceit $ forever (threadDelay maxBound)-  Conceit as <|> Conceit bs =-    Conceit $ fmap (fmap (either id id)) $ race as bs--instance (Monoid a) => Monoid (Conceit e a) where-   mempty = Conceit . pure . pure $ mempty-   mappend c1 c2 = (<>) <$> c1 <*> c2---- | `>>` sequences its arguments.-instance Monad (Conceit e) where-   return = pure-   f >>= k = Conceit $ do-      x <- runConceit f-      case x of -         Left e -> return $ Left e                      -         Right r -> runConceit $ k r--instance MonadPlus (Conceit e) where-   mzero = empty-   mplus = (<|>)--instance MonadIO (Conceit e) where-   liftIO = _Conceit---- | `<!>` makes its two arguments race against each other.-instance Alt (Conceit e) where-    (<!>) = (<|>)---- | `zero` is a computation that never finishes.-instance Plus (Conceit e) where-    zero = empty---- | `>>-` is sequential.-instance Bind (Conceit s) where-    (>>-) = (>>=)---- | `<.>` is concurrent.-instance Apply (Conceit s) where-    (<.>) = (<*>) -    (<.) = (<*) -    (.>) = (*>) ---#if MIN_VERSION_mtl(2, 2, 1)-instance MonadError e (Conceit e) where-     throwError = Conceit . pure . Left-     Conceit c `catchError`  h = -        Conceit $ runExceptT $ ExceptT c `catchError` (ExceptT . runConceit . h)-#endif---- | Throws exceptions into IO.-instance Ex.MonadThrow (Conceit e) where-    throwM = Conceit . Ex.throwM---- | Catches exceptions from IO.-instance Ex.MonadCatch (Conceit e) where-      catch (Conceit m) f = Conceit $ Ex.catch m (runConceit . f)--_Conceit :: IO a -> Conceit e a-_Conceit = Conceit . fmap pure  --_runConceit :: Conceit Void a -> IO a-_runConceit c = either absurd id <$> runConceit c --{-| -      Works similarly to 'Control.Concurrent.Async.mapConcurrently' from the-@async@ package, but if any of the computations fails with @e@, the others are-immediately cancelled and the whole computation fails with @e@. - -}-mapConceit :: (Traversable t) => (a -> IO (Either e b)) -> t a -> IO (Either e (t b))-mapConceit f = runConceit . sequenceA . fmap (Conceit . f)--catchAll :: IO a -> (SomeException -> IO a) -> IO a-catchAll = catch---- Adapted from the race function from async-race :: IO (Either e a) -> IO (Either e b) -> IO (Either e (Either a b)) -race left right = conceit' left right collect-  where-    collect m = do-        e <- takeMVar m-        case e of-            Left ex -> throwIO ex-            Right (Right (Right r1)) -> return $ Right $ Right r1-            Right (Right (Left e1)) -> return $ Left e1 -            Right (Left (Right r2)) -> return $ Right $ Left r2 -            Right (Left (Left e2)) -> return $ Left e2---- Adapted from the concurrently function from async-conceit :: IO (Either e a) -> IO (Either e b) -> IO (Either e (a, b))-conceit left right = conceit' left right (collect [])-  where-    collect [Left (Right a), Right (Right b)] _ = return $ Right (a,b)-    collect [Right (Right b), Left (Right a)] _ = return $ Right (a,b)-    collect (Left (Left ea):_) _ = return $ Left ea-    collect (Right (Left eb):_) _ = return $ Left eb-    collect xs m = do-        e <- takeMVar m-        case e of-            Left ex -> throwIO ex-            Right r -> collect (r:xs) m---- Verbatim copy of the internal concurrently' function from async-conceit' :: IO a -> IO b-         -> (MVar (Either SomeException (Either a b)) -> IO r)-         -> IO r-conceit' left right collect = do-    done <- newEmptyMVar-    mask $ \restore -> do-        lid <- forkIO $ restore (left >>= putMVar done . Right . Left)-                             `catchAll` (putMVar done . Left)-        rid <- forkIO $ restore (right >>= putMVar done . Right . Right)-                             `catchAll` (putMVar done . Left)-        let stop = killThread lid >> killThread rid-        r <- restore (collect done) `onException` stop-        stop-        return r-+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE CPP #-}
+
+module Control.Concurrent.Conceit ( 
+          Conceit (..)
+        , _Conceit
+        , _runConceit
+        , conceit
+        , mapConceit
+    ) where
+
+import Data.Bifunctor
+import Data.Monoid
+import Data.Typeable
+import Data.Traversable
+import Data.Void
+import Control.Applicative 
+import Control.Monad
+import Control.Monad.IO.Class
+import qualified Control.Monad.Catch as Ex
+import Control.Exception 
+import Control.Concurrent
+import Data.Functor.Bind
+import Data.Functor.Plus
+
+#if MIN_VERSION_mtl(2, 2, 1)
+import Control.Monad.Except
+#endif
+
+{-| 
+    'Conceit' is very similar to 'Control.Concurrent.Async.Concurrently' from the
+@async@ package, but it has an explicit error type @e@.
+
+   The 'Applicative' instance runs two actions concurrently, waits until
+they finish, and combines their results. 
+
+   However, if any of the actions fails with @e@ the other action is
+   immediately cancelled and the whole computation fails with @e@. 
+
+    To put it another way: 'Conceit' behaves like 'Concurrently' for
+    successes and like 'race' for errors.  
+-}
+newtype Conceit e a = Conceit { runConceit :: IO (Either e a) } deriving Functor
+
+instance Bifunctor Conceit where
+  bimap f g (Conceit x) = Conceit $ liftM (bimap f g) x
+
+instance Applicative (Conceit e) where
+  pure = Conceit . pure . pure
+  Conceit fs <*> Conceit as =
+         Conceit $ fmap (fmap (\(f, a) -> f a)) $ conceit fs as
+
+instance Alternative (Conceit e) where
+  empty = Conceit $ forever (threadDelay maxBound)
+  Conceit as <|> Conceit bs =
+    Conceit $ fmap (fmap (either id id)) $ race as bs
+
+instance (Monoid a) => Monoid (Conceit e a) where
+   mempty = Conceit . pure . pure $ mempty
+   mappend c1 c2 = (<>) <$> c1 <*> c2
+
+-- | `>>` sequences its arguments.
+instance Monad (Conceit e) where
+   return = pure
+   f >>= k = Conceit $ do
+      x <- runConceit f
+      case x of 
+         Left e -> return $ Left e                      
+         Right r -> runConceit $ k r
+
+instance MonadPlus (Conceit e) where
+   mzero = empty
+   mplus = (<|>)
+
+instance MonadIO (Conceit e) where
+   liftIO = _Conceit
+
+-- | `<!>` makes its two arguments race against each other.
+instance Data.Functor.Plus.Alt (Conceit e) where
+    (<!>) = (<|>)
+
+-- | `zero` is a computation that never finishes.
+instance Plus (Conceit e) where
+    zero = empty
+
+-- | `>>-` is sequential.
+instance Bind (Conceit s) where
+    (>>-) = (>>=)
+
+-- | `<.>` is concurrent.
+instance Apply (Conceit s) where
+    (<.>) = (<*>) 
+    (<.) = (<*) 
+    (.>) = (*>) 
+
+
+#if MIN_VERSION_mtl(2, 2, 1)
+instance MonadError e (Conceit e) where
+     throwError = Conceit . pure . Left
+     Conceit c `catchError`  h = 
+        Conceit $ runExceptT $ ExceptT c `catchError` (ExceptT . runConceit . h)
+#endif
+
+-- | Throws exceptions into IO.
+instance Ex.MonadThrow (Conceit e) where
+    throwM = Conceit . Ex.throwM
+
+-- | Catches exceptions from IO.
+instance Ex.MonadCatch (Conceit e) where
+      catch (Conceit m) f = Conceit $ Ex.catch m (runConceit . f)
+
+_Conceit :: IO a -> Conceit e a
+_Conceit = Conceit . fmap pure  
+
+_runConceit :: Conceit Void a -> IO a
+_runConceit c = either absurd id <$> runConceit c 
+
+{-| 
+      Works similarly to 'Control.Concurrent.Async.mapConcurrently' from the
+@async@ package, but if any of the computations fails with @e@, the others are
+immediately cancelled and the whole computation fails with @e@. 
+ -}
+mapConceit :: (Traversable t) => (a -> IO (Either e b)) -> t a -> IO (Either e (t b))
+mapConceit f = runConceit . sequenceA . fmap (Conceit . f)
+
+catchAll :: IO a -> (SomeException -> IO a) -> IO a
+catchAll = catch
+
+-- Adapted from the race function from async
+race :: IO (Either e a) -> IO (Either e b) -> IO (Either e (Either a b)) 
+race left right = conceit' left right collect
+  where
+    collect m = do
+        e <- takeMVar m
+        case e of
+            Left ex -> throwIO ex
+            Right (Right (Right r1)) -> return $ Right $ Right r1
+            Right (Right (Left e1)) -> return $ Left e1 
+            Right (Left (Right r2)) -> return $ Right $ Left r2 
+            Right (Left (Left e2)) -> return $ Left e2
+
+-- Adapted from the concurrently function from async
+conceit :: IO (Either e a) -> IO (Either e b) -> IO (Either e (a, b))
+conceit left right = conceit' left right (collect [])
+  where
+    collect [Left (Right a), Right (Right b)] _ = return $ Right (a,b)
+    collect [Right (Right b), Left (Right a)] _ = return $ Right (a,b)
+    collect (Left (Left ea):_) _ = return $ Left ea
+    collect (Right (Left eb):_) _ = return $ Left eb
+    collect xs m = do
+        e <- takeMVar m
+        case e of
+            Left ex -> throwIO ex
+            Right r -> collect (r:xs) m
+
+-- Verbatim copy of the internal concurrently' function from async
+conceit' :: IO a -> IO b
+         -> (MVar (Either SomeException (Either a b)) -> IO r)
+         -> IO r
+conceit' left right collect = do
+    done <- newEmptyMVar
+    mask $ \restore -> do
+        lid <- forkIO $ restore (left >>= putMVar done . Right . Left)
+                             `catchAll` (putMVar done . Left)
+        rid <- forkIO $ restore (right >>= putMVar done . Right . Right)
+                             `catchAll` (putMVar done . Left)
+        let stop = killThread lid >> killThread rid
+        r <- restore (collect done) `onException` stop
+        stop
+        return r
+