packages feed

drinkery 0.1 → 0.2

raw patch · 7 files changed

+253/−100 lines, 7 filesdep +exceptionsdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: exceptions

Dependency ranges changed: base

API changes (from Hackage documentation)

- Data.Drinkery.Distiller: filteringMaybe :: (Monoid r, Monad m) => (a -> Bool) -> Still r (Maybe a) r (Maybe a) m
- Data.Drinkery.Distiller: scanningMaybe :: (Monoid r, Monad m) => (b -> a -> b) -> b -> Still r (Maybe a) r (Maybe b) m
- Data.Drinkery.Distiller: type Still p q r s m = Distiller (Tap p q) r s m
+ Data.Drinkery.Distiller: echo :: Monad m => Distiller (Tap r s) r s m
+ Data.Drinkery.Distiller: repeating :: (MonadDrunk (Tap r a) m, Semigroup r) => m b -> Tap r b m
+ Data.Drinkery.Distiller: reservingTap :: MonadDrunk (Tap r a) m => (a -> m (s, Tap r s m)) -> Tap r s m
+ Data.Drinkery.IO: tapPopper :: (Monoid r, CloseRequest r) => Tap r s IO -> (IO s -> IO ()) -> IO ()
+ Data.Drinkery.Patron: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Data.Drinkery.Patron.Patron s m)
+ Data.Drinkery.Patron: lookAheadT :: (Monad m, MonadTrans t, Monoid r, Semigroup r, MonadDrunk (Tap r s) (t m)) => Patron s m a -> t m a
+ Data.Drinkery.Still: drinkUp :: (Monoid r, Semigroup r, MonadDrunk (Tap r (Maybe s)) m) => m [s]
+ Data.Drinkery.Still: filter :: Monad m => (a -> Bool) -> Pipe a a m
+ Data.Drinkery.Still: map :: (Functor t, Monad m) => (a -> b) -> Distiller (Tap r (t a)) r (t b) m
+ Data.Drinkery.Still: mapAccum :: Monad m => (s -> a -> (s, b)) -> s -> Pipe a b m
+ Data.Drinkery.Still: mapMaybe :: (Monad m) => (a -> Maybe b) -> Pipe a b m
+ Data.Drinkery.Still: reserve :: (Monoid r, MonadDrunk (Cask r s) m) => (s -> Barman r (Maybe t) m ()) -> Barman r (Maybe t) m ()
+ Data.Drinkery.Still: scan :: Monad m => (b -> a -> b) -> b -> Pipe a b m
+ Data.Drinkery.Still: sip :: (Monoid r, Alternative m, MonadDrunk (Tap r (Maybe s)) m) => m s
+ Data.Drinkery.Still: type Cask r s = Tap r (Maybe s)
+ Data.Drinkery.Still: type Pipe a b m = forall r. (Monoid r, Semigroup r) => Still r a r b m
+ Data.Drinkery.Tap: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Data.Drinkery.Tap.Barman r s m)
+ Data.Drinkery.Tap: repeatTap :: Applicative m => s -> Tap r s m
+ Data.Drinkery.Tap: repeatTapM :: Applicative m => m s -> Tap r s m
+ Data.Drinkery.Tap: repeatTapM' :: Applicative m => m s -> Tap () s m
+ Data.Drinkery.Tap: retractSommelier :: Monad m => Sommelier () m s -> m ()
- Data.Drinkery.Distiller: (+&) :: (Closable tap, Monad m) => tap m -> Drinker tap m a -> m a
+ Data.Drinkery.Distiller: (+&) :: (Closable tap, MonadCatch m) => tap m -> Drinker tap m a -> m a
- Data.Drinkery.Distiller: filtering :: (Monoid r, Monad m) => (a -> Bool) -> Still r a r a m
+ Data.Drinkery.Distiller: filtering :: (Monoid r, Monad m) => (a -> Bool) -> Distiller (Tap r a) r a m
- Data.Drinkery.Distiller: mapping :: (Monoid r, Monad m) => (a -> b) -> Still r a r b m
+ Data.Drinkery.Distiller: mapping :: (Monad m) => (a -> b) -> Distiller (Tap r a) r b m
- Data.Drinkery.Distiller: scanning :: (Monoid r, Monad m) => (b -> a -> b) -> b -> Still r a r b m
+ Data.Drinkery.Distiller: scanning :: Monad m => (b -> a -> b) -> b -> Distiller (Tap r a) r b m
- Data.Drinkery.Distiller: traversing :: (Monoid r, Monad m) => (a -> m b) -> Still r a r b m
+ Data.Drinkery.Distiller: traversing :: (Monad m) => (a -> m b) -> Distiller (Tap r a) r b m
- Data.Drinkery.Tap: consTap :: (Monoid r, Applicative m) => s -> Tap r s m -> Tap r s m
+ Data.Drinkery.Tap: consTap :: (Semigroup r, Applicative m) => s -> Tap r s m -> Tap r s m
- Data.Drinkery.Tap: leftover :: (Monoid r, MonadDrunk (Tap r s) m) => s -> m ()
+ Data.Drinkery.Tap: leftover :: (Semigroup r, MonadDrunk (Tap r s) m) => s -> m ()
- Data.Drinkery.Tap: makeTap :: (Monoid r, Monad m) => m (Tap r s m) -> Tap r s m
+ Data.Drinkery.Tap: makeTap :: (Monad m) => m (Tap r s m) -> Tap r s m
- Data.Drinkery.Tap: orderTap :: (Monoid r) => r -> Tap r s m -> Tap r s m
+ Data.Drinkery.Tap: orderTap :: (Semigroup r) => r -> Tap r s m -> Tap r s m
- Data.Drinkery.Tap: pour :: (Monoid r, Applicative f, Applicative m) => s -> Barman r (f s) m ()
+ Data.Drinkery.Tap: pour :: (Semigroup r, Applicative m) => s -> Barman r s m ()
- Data.Drinkery.Tap: request :: (Monoid r, MonadDrunk (Tap r s) m) => r -> m ()
+ Data.Drinkery.Tap: request :: (Semigroup r, MonadDrunk (Tap r s) m) => r -> m ()
- Data.Drinkery.Tap: runSommelier :: (Monoid r, Applicative m, Alternative f) => Sommelier r m s -> Tap r (f s) m
+ Data.Drinkery.Tap: runSommelier :: (Semigroup r, Applicative m, Alternative f) => Sommelier r m s -> Tap r (f s) m
- Data.Drinkery.Tap: smell :: (Monoid r, MonadDrunk (Tap r s) m) => m s
+ Data.Drinkery.Tap: smell :: (Monoid r, Semigroup r, MonadDrunk (Tap r s) m) => m s
- Data.Drinkery.Tap: yield :: (Monoid r, Applicative m) => s -> Barman r s m ()
+ Data.Drinkery.Tap: yield :: (Semigroup r, Applicative f, Applicative m) => s -> Barman r (f s) m ()

Files

benchmarks/benchmark.hs view
@@ -4,8 +4,8 @@ import Data.List
 import Data.Void
 import Gauge.Main
-import qualified Control.Monad.Trans.List as L
 import qualified Data.Drinkery as D
+import qualified Data.Drinkery.Still as D
 import qualified ListT as L
 import qualified Pipes as P
 import qualified Pipes.Prelude as P
@@ -28,7 +28,7 @@ sourceSeq k = forM_ [1..50] $ \a -> forM_ [1..a] $ \b -> forM_ [1..b] $ \c -> k $! a + b + c
 {-# INLINE sourceSeq #-}
 
-sourceD :: Monad m => D.Tap () (Maybe Int) m
+sourceD :: Monad m => D.Cask () Int m
 sourceD = D.runSommelier (sourceAlt D.taste)
 {-# INLINE sourceD #-}
 
@@ -36,7 +36,7 @@ sourceP = sourceSeq P.yield
 {-# INLINE sourceP #-}
 
-sourceC :: Monad m => C.Producer m Int
+sourceC :: Monad m => C.ConduitT i Int m ()
 sourceC = sourceSeq C.yield
 {-# INLINE sourceC #-}
 
@@ -48,7 +48,7 @@   [ bgroup "drain"
       [ bench "drinkery/Barman" $ whnfIO
           $ apply (D.+& drainD)
-          $ D.runBarman (sourceSeq D.pour)
+          $ D.runBarman (sourceSeq D.yield)
       , bench "drinkery/Sommelier" $ whnfIO
           $ apply (D.+& drainD) sourceD
       , bench "pipes/Producer" $ whnfIO
@@ -58,30 +58,27 @@           $ P.enumerate (sourceAlt (P.Select . P.each))
       , bench "list-t" $ whnfIO
           $ apply (L.traverse_ $ const $ pure ())
-          $ sourceAlt L.fromFoldable-      , bench "ListT" $ whnfIO
-          $ apply (L.foldlM (\_ _ -> pure ()) ())
-          $ sourceAlt L.fromList
+          $ sourceAlt L.fromFoldable
       ]
   , bgroup "scan"
       [ bench "drinkery" $ whnfIO $ apply (\h -> sourceD D.+& h D.$& drainD)
-          $ D.scanningMaybe (+) 0
+          $ D.scan (+) 0
       , bench "pipes" $ whnfIO $ apply (\p -> P.runEffect $ P.for (sourceP P.>-> p) P.discard)
           $ P.scan (+) 0 id
-      , bench "conduit" $ whnfIO $ apply (\h -> sourceC C.$= h C.$$ CC.sinkNull)
-          $ CC.scanl (+) 0
+      , bench "conduit" $ whnfIO $ C.runConduit $ apply (\(h, s) -> sourceC C..| h C..| s)
+          (CC.scanl (+) 0, CC.sinkNull)
       , bench "machines" $ whnfIO $ apply (M.runT_ . (sourceM M.~>))
           $ M.scan (+) 0
       ]
    , bgroup "scan-chain"
-      [ bench "drinkery/++$" $ whnfIO $ apply (\h -> D.runBarman (sourceSeq D.pour) D.+& h D.$& drainD)
-          $ D.scanningMaybe (+) 0 D.++$ D.scanningMaybe (+) 0
-      , bench "drinkery/$&" $ whnfIO $ apply (\(h, h') -> D.runBarman (sourceSeq D.pour) D.+& h D.$& h' D.$& drainD)
-          (D.scanningMaybe (+) 0, D.scanningMaybe (+) 0)
+      [ bench "drinkery/++$" $ whnfIO $ apply (\h -> D.runBarman (sourceSeq D.yield) D.+& h D.$& drainD)
+          $ D.scan (+) 0 D.++$ D.scan (+) 0
+      , bench "drinkery/$&" $ whnfIO $ apply (\(h, h') -> D.runBarman (sourceSeq D.yield) D.+& h D.$& h' D.$& drainD)
+          (D.scan (+) 0, D.scan (+) 0)
       , bench "pipes" $ whnfIO $ apply (\p -> P.runEffect $ P.for (sourceP P.>-> p) P.discard)
           $ P.scan (+) 0 id P.>-> P.scan (+) 0 id
-      , bench "conduit" $ whnfIO $ apply (\h -> sourceC C.$= h C.$$ CC.sinkNull)
-          $ CC.scanl (+) 0 C.=$= CC.scanl (+) 0
+      , bench "conduit" $ whnfIO $ apply (\(h, s) -> C.runConduit $ sourceC C..| h C..| s)
+          (CC.scanl (+) 0 C..| CC.scanl (+) 0, CC.sinkNull)
       , bench "machines" $ whnfIO $ apply (M.runT_ . (sourceM M.~>))
           $ M.scan (+) 0 M.~> M.scan (+) 0
       ]
drinkery.cabal view
@@ -1,39 +1,72 @@-name:                drinkery-version:             0.1-synopsis:            Boozy streaming library-description:         Boozy streaming library-homepage:            https://github.com/fumieval/drinkery#readme-license:             BSD3-license-file:        LICENSE-author:              Fumiaki Kinoshita-maintainer:          fumiexcel@gmail.com-copyright:           Copyright (c) 2017 Fumiaki Kinoshita-category:            Data-build-type:          Simple-extra-source-files:  README.md-cabal-version:       >=1.10+-- This file has been generated from package.yaml by hpack version 0.20.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: c680196ca0c264db17dcb6cca154fa3a64e957e2d4859e8dd024c4b302e0f731 -library-  hs-source-dirs:      src-  exposed-modules:-    Data.Drinkery-    Data.Drinkery.Class-    Data.Drinkery.Combinators-    Data.Drinkery.Distiller-    Data.Drinkery.Patron-    Data.Drinkery.Tap-  build-depends:       base >= 4.7 && < 5, transformers, mtl-  ghc-options: -Wall-  default-language:    Haskell2010+name:           drinkery+version:        0.2+synopsis:       Boozy streaming library+description:    Please see the README on Github at <https://github.com/fumieval/drinkery#readme>+category:       Control+homepage:       https://github.com/fumieval/drinkery#readme+bug-reports:    https://github.com/fumieval/drinkery/issues+author:         Fumiaki Kinoshita+maintainer:     fumiexcel@gmail.com+copyright:      Copyright (c) 2017 Fumiaki Kinoshita+license:        BSD3+license-file:   LICENSE+build-type:     Simple+cabal-version:  >= 1.10 -benchmark benchmark-  type:           exitcode-stdio-1.0-  main-is:        benchmark.hs-  ghc-options:    -O2-  hs-source-dirs: benchmarks-  build-depends: base, drinkery, gauge, pipes, machines, conduit, conduit-combinators, list-t, ListT-  default-language:    Haskell2010+extra-source-files:+    README.md  source-repository head-  type:     git+  type: git   location: https://github.com/fumieval/drinkery++library+  hs-source-dirs:+      src+  ghc-options: -Wall+  build-depends:+      base <=5+    , exceptions+    , mtl+    , transformers+  exposed-modules:+      Data.Drinkery+      Data.Drinkery.Class+      Data.Drinkery.Combinators+      Data.Drinkery.Distiller+      Data.Drinkery.IO+      Data.Drinkery.Patron+      Data.Drinkery.Still+      Data.Drinkery.Tap+  other-modules:+      Paths_drinkery+  default-language: Haskell2010++benchmark benchmark+  type: exitcode-stdio-1.0+  main-is: benchmark.hs+  hs-source-dirs:+      benchmarks+  ghc-options: -O2+  build-depends:+      ListT+    , base+    , conduit+    , conduit-combinators+    , drinkery+    , exceptions+    , gauge+    , list-t+    , machines+    , mtl+    , pipes+    , transformers+  other-modules:+      Paths_drinkery+  default-language: Haskell2010
src/Data/Drinkery/Distiller.hs view
@@ -18,18 +18,20 @@   , (++$)   , (++&)   -- * Stock distillers-  , Still-  , scanningMaybe-  , filteringMaybe+  , reservingTap+  , echo   , mapping   , traversing   , filtering   , scanning+  , repeating   ) where +import Control.Monad.Catch (onException, MonadCatch) import Control.Monad.Trans import Data.Drinkery.Tap import Data.Drinkery.Class+import Data.Semigroup import Data.Tuple  -- | @Distiller tap m r s@ is a stream transducer which has four parameters:@@ -74,9 +76,9 @@ {-# INLINE (++$) #-}  -- | Feed a tap to a drinker and close the used tap.-(+&) :: (Closable tap, Monad m) => tap m -> Drinker tap m a -> m a+(+&) :: (Closable tap, MonadCatch m) => tap m -> Drinker tap m a -> m a t +& b = do-  (a, t') <- runDrinker b t+  (a, t') <- runDrinker b t `onException` close t   close t'   return a {-# INLINE (+&) #-}@@ -89,43 +91,46 @@ t $& b = fmap fst $ runDrinker b t {-# INLINE ($&) #-} --- | Mono in/out-type Still p q r s m = Distiller (Tap p q) r s m--scanningMaybe :: (Monoid r, Monad m) => (b -> a -> b) -> b -> Still r (Maybe a) r (Maybe b) m-scanningMaybe f b0 = consTap (Just b0) $ go b0 where-  go b = Tap $ \r -> Drinker $ \tap -> do-    (m, t') <- unTap tap r-    case m of-      Just a -> let !b' = f b a in return ((Just b', go b'), t')-      Nothing -> return ((Nothing, go b), t')-{-# INLINE scanningMaybe #-}--filteringMaybe :: (Monoid r, Monad m) => (a -> Bool) -> Still r (Maybe a) r (Maybe a) m-filteringMaybe = filtering . maybe True-{-# INLINE filteringMaybe #-}---- | Create a request-preserving distiller.-propagating :: (Monoid r, Monad m) => Drinker (Tap r a) m (b, Still r a r b m) -> Still r a r b m-propagating m = Tap $ \r -> request r >> m-{-# INLINE propagating #-}+echo :: Monad m => Distiller (Tap r s) r s m+echo = mapping id -mapping :: (Monoid r, Monad m) => (a -> b) -> Still r a r b m+mapping :: (Monad m) => (a -> b) -> Distiller (Tap r a) r b m mapping f = go where-  go = propagating $ drink >>= \a -> return (f a, go)+  go = Tap $ \r -> drinking $ \t -> fmap (\(s, t') -> ((f s, go), t')) $ unTap t r {-# INLINE mapping #-} -traversing :: (Monoid r, Monad m) => (a -> m b) -> Still r a r b m+-- | Get one element preserving a request+reservingTap :: MonadDrunk (Tap r a) m => (a -> m (s, Tap r s m)) -> Tap r s m+reservingTap k = Tap $ \r -> do+  a <- drinking $ \t -> unTap t r+  k a+{-# INLINE reservingTap #-}++traversing :: (Monad m) => (a -> m b) -> Distiller (Tap r a) r b m traversing f = go where-  go = propagating $ drink >>= \a -> lift (f a) >>= \b -> return (b, go)+  go = reservingTap $ \a -> do+    b <- lift $ f a+    return (b, go)+{-# INLINE traversing #-} -filtering :: (Monoid r, Monad m) => (a -> Bool) -> Still r a r a m+filtering :: (Monoid r, Monad m) => (a -> Bool) -> Distiller (Tap r a) r a m filtering f = go where-  go = propagating $ drink >>= \a -> if f a+  go = reservingTap $ \a -> if f a     then return (a, go)     else unTap go mempty+{-# INLINE filtering #-} -scanning :: (Monoid r, Monad m) => (b -> a -> b) -> b -> Still r a r b m-scanning f b0 = consTap b0 $ go b0 where-  go b = propagating $ fmap (\a -> let !b' = f b a in (b', go $ b')) drink+scanning :: Monad m => (b -> a -> b) -> b -> Distiller (Tap r a) r b m+scanning f b0 = go b0 where+  go b = reservingTap $ \a -> do+    let !b' = f b a+    return (b', go $ b') {-# INLINE scanning #-}++-- | Create a request-preserving distiller from a drinker action.+repeating :: (MonadDrunk (Tap r a) m, Semigroup r) => m b -> Tap r b m+repeating m = go where+  go = Tap $ \r -> do+    request r+    a <- m+    return (a, go)
+ src/Data/Drinkery/IO.hs view
@@ -0,0 +1,20 @@+module Data.Drinkery.IO where++import Control.Exception+import Data.Drinkery.Class+import Data.Drinkery.Tap+import Data.IORef++-- | Create a popper from a 'Tap'.+--+-- @tapPopper :: CloseRequest r => Tap r s IO -> GivesPopper@+--+tapPopper :: (Monoid r, CloseRequest r) => Tap r s IO -> (IO s -> IO ()) -> IO ()+tapPopper tap0 needsPopper = do+  vTap <- newIORef tap0+  let popper = do+        t <- readIORef vTap+        (s, t') <- unTap t mempty+        writeIORef vTap t'+        return s+  needsPopper popper `finally` do readIORef vTap >>= close
src/Data/Drinkery/Patron.hs view
@@ -1,9 +1,12 @@-{-# LANGUAGE LambdaCase, DeriveFunctor #-}+{-# LANGUAGE LambdaCase, DeriveFunctor, FlexibleContexts #-} module Data.Drinkery.Patron where  import Control.Applicative import Control.Monad import Control.Monad.Trans+import Data.Drinkery.Class+import Data.Drinkery.Tap+import Data.Semigroup  -- | @Patron s@ is a simple consumer of @s@. Unlike 'Drinker', it can be -- partially run.@@ -45,6 +48,9 @@   mzero = empty   mplus = (<|>) +instance MonadIO m => MonadIO (Patron s m) where+  liftIO = Patron . fmap Right . liftIO+ await :: Monad m => Patron s m s await = Patron $ pure $ Left pure {-# INLINE await #-}@@ -76,3 +82,9 @@     Left f -> k >>= go . f     Right a -> return a {-# INLINE iterPatronT #-}++lookAheadT :: (Monad m, MonadTrans t, Monoid r, Semigroup r, MonadDrunk (Tap r s) (t m)) => Patron s m a -> t m a+lookAheadT = go [] where+  go xs m = lift (runPatron m) >>= \case+    Right a -> a <$ mapM_ leftover (reverse xs)+    Left f -> drink >>= \s -> go (s : xs) (f s)
+ src/Data/Drinkery/Still.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE BangPatterns, Rank2Types, FlexibleContexts, LambdaCase #-}+module Data.Drinkery.Still where++import Control.Applicative+import Data.Drinkery.Class+import Data.Drinkery.Distiller+import Data.Drinkery.Tap+import Data.Semigroup++type Cask r s = Tap r (Maybe s)++-- | Mono in/out+type Still p q r s m = Cask r s (Drinker (Cask p q) m)++type Pipe a b m = forall r. (Monoid r, Semigroup r) => Still r a r b m++scan :: Monad m => (b -> a -> b) -> b -> Pipe a b m+scan f b0 = consTap (Just b0) $ go b0 where+  go b = Tap $ \r -> Drinker $ \tap -> do+    (m, t') <- unTap tap r+    case m of+      Just a -> let !b' = f b a in return ((Just b', go b'), t')+      Nothing -> return ((Nothing, go b), t')+{-# INLINE scan #-}++reserve :: (Monoid r, MonadDrunk (Cask r s) m)+    => (s -> Barman r (Maybe t) m ()) -> Barman r (Maybe t) m ()+reserve k = Barman $ \cont -> Tap $ \r -> drinking (\t -> unTap t r) >>= \case+  Nothing -> return (Nothing, cont ())+  Just s -> unTap (unBarman (k s) cont) mempty++map :: (Functor t, Monad m) => (a -> b) -> Distiller (Tap r (t a)) r (t b) m+map = mapping . fmap+{-# INLINE map #-}++mapMaybe :: (Monad m) => (a -> Maybe b) -> Pipe a b m+mapMaybe f = inexhaustible $ reserve $ mapM_ yield . f+{-# INLINE mapMaybe #-}++filter :: Monad m => (a -> Bool) -> Pipe a a m+filter = filtering . maybe True+{-# INLINE filter #-}++mapAccum :: Monad m => (s -> a -> (s, b)) -> s -> Pipe a b m+mapAccum f = go where+  go s = Tap $ \r -> Drinker $ \tap -> do+    (m, t') <- unTap tap r+    case m of+      Just a -> let (s', b) = f s a in return ((Just b, go s'), t')+      Nothing -> return ((Nothing, go s), t')+{-# INLINE mapAccum #-}++-- | Consume all the content of a 'Tap' and return the elements as a list.+drinkUp :: (Monoid r, Semigroup r, MonadDrunk (Tap r (Maybe s)) m) => m [s]+drinkUp = drink >>= maybe (pure []) (\x -> (x:) <$> drinkUp)++sip :: (Monoid r, Alternative m, MonadDrunk (Tap r (Maybe s)) m) => m s+sip = drink >>= maybe empty pure+{-# INLINE sip #-}
src/Data/Drinkery/Tap.hs view
@@ -15,6 +15,9 @@   , consTap   , orderTap   , makeTap+  , repeatTap+  , repeatTapM+  , repeatTapM'   -- * Barman   , Barman(..)   , yield@@ -29,6 +32,7 @@   , inquire   , runSommelier   , runSommelier'+  , retractSommelier   -- * Drinker   , drink   , leftover@@ -42,6 +46,7 @@ import Control.Monad import Control.Monad.IO.Class import Control.Monad.Trans.Class+import Data.Semigroup import Data.Drinkery.Class  -- | @'Tap' m r s@ is a non-monadic, endless producer of @s@. It takes a request@@ -49,20 +54,34 @@ newtype Tap r s m = Tap { unTap :: r -> m (s, Tap r s m) }  -- | Prepend a new element, delaying requests.-consTap :: (Monoid r, Applicative m) => s -> Tap r s m -> Tap r s m-consTap s t = Tap $ \r -> pure (s, Tap $ unTap t . mappend r)+consTap :: (Semigroup r, Applicative m) => s -> Tap r s m -> Tap r s m+consTap s t = Tap $ \r -> pure (s, Tap $ unTap t . (<>) r) {-# INLINE consTap #-}  -- | Send a request to a 'Tap'.-orderTap :: (Monoid r) => r -> Tap r s m -> Tap r s m-orderTap r t = Tap $ \r' -> unTap t $! mappend r r'+orderTap :: (Semigroup r) => r -> Tap r s m -> Tap r s m+orderTap r t = Tap $ \r' -> unTap t $! r <> r' {-# INLINE orderTap #-}  -- | Involve an action.-makeTap :: (Monoid r, Monad m) => m (Tap r s m) -> Tap r s m+makeTap :: (Monad m) => m (Tap r s m) -> Tap r s m makeTap m = Tap $ \r -> m >>= \t -> unTap t r {-# INLINE makeTap #-} +repeatTap :: Applicative m => s -> Tap r s m+repeatTap s = go where+  go = Tap $ const $ pure (s, go)+{-# INLINE repeatTap #-}++repeatTapM :: Applicative m => m s -> Tap r s m+repeatTapM m = go where+  go = Tap $ const $ flip (,) go <$> m+{-# INLINE repeatTapM #-}++repeatTapM' :: Applicative m => m s -> Tap () s m+repeatTapM' = repeatTapM+{-# INLINE repeatTapM' #-}+ instance CloseRequest r => Closable (Tap r s) where   close t = void $ unTap t closeRequest @@ -70,16 +89,16 @@ drink = drinking $ \t -> unTap t mempty {-# INLINE drink #-} -leftover :: (Monoid r, MonadDrunk (Tap r s) m) => s -> m ()+leftover :: (Semigroup r, MonadDrunk (Tap r s) m) => s -> m () leftover s = drinking $ \t -> return ((), consTap s t) {-# INLINE leftover #-} -request :: (Monoid r, MonadDrunk (Tap r s) m) => r -> m ()+request :: (Semigroup r, MonadDrunk (Tap r s) m) => r -> m () request r = drinking $ \t -> return ((), orderTap r t) {-# INLINE request #-}  -- | Get one element without consuming.-smell :: (Monoid r, MonadDrunk (Tap r s) m) => m s+smell :: (Monoid r, Semigroup r, MonadDrunk (Tap r s) m) => m s smell = do   s <- drink   leftover s@@ -103,12 +122,15 @@ instance MonadTrans (Barman r s) where   lift m = Barman $ \k -> Tap $ \rs -> m >>= \a -> unTap (k a) rs +instance MonadIO m => MonadIO (Barman r s m) where+  liftIO m = Barman $ \k -> Tap $ \rs -> liftIO m >>= \a -> unTap (k a) rs+ instance MonadDrunk t m => MonadDrunk t (Barman p q m) where   drinking f = lift (drinking f)  -- | Produce one element. Orders are put off.-yield :: (Monoid r, Applicative m) => s -> Barman r s m ()-yield s = Barman $ \cont -> consTap s (cont ())+pour :: (Semigroup r, Applicative m) => s -> Barman r s m ()+pour s = Barman $ \cont -> consTap s (cont ())  -- | Accept orders and clear the queue. accept :: Monoid r => Barman r s m r@@ -163,7 +185,7 @@  -- | End of stream eof :: (Applicative m, Alternative f) => Tap r (f a) m-eof = Tap $ const $ pure (empty, eof)+eof = repeatTap empty  -- | Run a 'Barman' action and terminate the stream with 'eof'. runBarman :: (Monoid r, Applicative m, Alternative f) => Barman r (f s) m a -> Tap r (f s) m@@ -176,7 +198,7 @@ {-# INLINE runBarman' #-}  -- | Run 'Sommelier' and terminate the stream with 'eof'.-runSommelier :: (Monoid r, Applicative m, Alternative f) => Sommelier r m s -> Tap r (f s) m+runSommelier :: (Semigroup r, Applicative m, Alternative f) => Sommelier r m s -> Tap r (f s) m runSommelier m = unSommelier m (consTap . pure) eof {-# INLINE runSommelier #-} @@ -185,6 +207,11 @@ runSommelier' = runSommelier {-# INLINE runSommelier' #-} -pour :: (Monoid r, Applicative f, Applicative m) => s -> Barman r (f s) m ()-pour = yield . pure+retractSommelier :: Monad m => Sommelier () m s -> m ()+retractSommelier (Sommelier f) = go $ f (const $ consTap True) (repeatTap False) where+  go m = unTap m () >>= \(a, k) -> when a (go k)+{-# INLINE retractSommelier #-}++yield :: (Semigroup r, Applicative f, Applicative m) => s -> Barman r (f s) m ()+yield = pour . pure {-# INLINE pour #-}