diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Fumiaki Kinoshita (c) 2017
+
+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.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,89 @@
+# drinkery
+
+drinkery is a yet another stream processing library themed on liquors. While it
+offers a simple interface, it also tries to be as expressive as possible.
+
+## Producers
+
+drinkery supports three types of producers: `Barman`, `Sommelier`, and `Tap`.
+
+`Barman r s` is a monad transformer to produce a stream of type `s`. It is good
+at interactively serving values.
+`topup :: s -> Barman r s m a` is the primary action.
+A barman can also accept requests from the downstream using `accept`.
+
+`Sommelier r` is a list-like backtracking monad (also known as ListT done right).
+It is useful for sampling elements of containers with effects.
+`taste :: Foldable f => f s -> Sommelier r m s` samples elements in any `Foldable`
+container. `inquire` to interact with the downstream.
+
+`Tap` is an endless producer. This can be connected to a 'Patron' or a 'Distiller'.
+
+`Barman` and `Sommelier` are converted to `Tap`
+by `runBarman` and `runSommelier` respectively.
+
+## Consumer
+
+`Patron r s` is a monad transformer which consumes `s` and may request `r`.
+
+`MonadDrink` provides the actions of `Patron`:
+
+* `drink :: m s` Get one element.
+* `spit :: s -> m ()` Leave one element.
+* `call :: r -> m ()` Send a request.
+
+`(+&) :: (Monoid r, CloseRequest r, Monad m) => Tap m r s -> Patron r s m a -> m a`
+connects a tap with a patron.
+
+## Transducer
+
+`Distiller p q m r s` is a stream transducer which
+
+* Sends `p`
+* Consumes `q`
+* Receives `r`
+* Produces `s`
+
+It is actually a `Tap` where the underlying monad is `Patron`.
+
+There are three composition operators:
+
+* `$&` Distiller-patron
+* `$$$` Distiler-distiller
+* `++$` Tap-distiller
+
+`+`, `&`, and `$` means a tap, a patron, and a distiller respectively. The middle
+characters of these operators signify the resulting structures.
+
+## Why drinkery?
+
+drinkery is designed to be fully featured and complements other libraries' missing
+functionalities.
+
+### pipes
+
+`pipes` is quite similar in that both `Proxy` and `Distiller` are bidirectional.
+Still there are some differences:
+
+* `Distiller` does not terminate.
+* Unlike pipes' `>->`, `$$$` propagates inner requests:
+    * `($$$) :: Monoid r => Distiller p q m r s -> Distiller r s m t u -> Distiller p q m t u`
+    * `(>->) :: Proxy a' a () b m r	-> Proxy () b c' c m r -> Proxy a' a c' c m r`
+* `Patron`, the consumer monad, may leave unconsumed inputs.
+* `drinkery` has much fewer operators.
+
+### conduit
+
+Both `drinkery` and `conduit` support leftovers, closing operation, and end of stream.
+The main difference is interactivity.
+
+### machines
+
+`machines` has multi-channel consumers but `drinkery` doesn't.
+`machines` does not support leftovers, nor interactive producers.
+
+### iteratee
+
+`iteratee` has an ability to handle requests but those are untyped (`SomeException`).
+`drinkery` provides a more robust interface for handling requests.
+Two monadic producers - `Barman` and `Sommelier` - are easier to use.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/benchmarks/benchmark.hs b/benchmarks/benchmark.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/benchmark.hs
@@ -0,0 +1,23 @@
+import qualified Data.Drinkery as D
+import qualified Data.Drinkery.Glass as D
+import Data.Functor.Identity
+import Control.Arrow
+import Control.Monad
+import Criterion.Main
+import Data.List
+import Data.Void
+
+drainD :: D.Distiller () (Maybe Int) IO () (Maybe a) -> IO ()
+drainD h = sourceD D.+& h D.$& D.sinkNull
+
+value :: Int
+value = 10000
+
+sourceD :: (Monoid r, Monad m) => D.Tap m r (Maybe Int)
+sourceD = D.runSommelier $ D.taste [1..value]
+
+main = defaultMain
+  [ bgroup "scan"
+      [ bench "drinkery" $ whnfIO $ drainD (D.scanningMaybe (+) 0)
+      ]
+  ]
diff --git a/drinkery.cabal b/drinkery.cabal
new file mode 100644
--- /dev/null
+++ b/drinkery.cabal
@@ -0,0 +1,39 @@
+name:                drinkery
+version:             0
+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
+
+library
+  hs-source-dirs:      src
+  exposed-modules:
+    Data.Drinkery
+    Data.Drinkery.Class
+    Data.Drinkery.Boozer
+    Data.Drinkery.Distiller
+    Data.Drinkery.Glass
+    Data.Drinkery.Tap
+  build-depends:       base >= 4.7 && < 5, transformers, mtl
+  ghc-options: -Wall
+  default-language:    Haskell2010
+
+benchmark benchmark
+  type:           exitcode-stdio-1.0
+  main-is:        benchmark.hs
+  ghc-options:    -O2
+  hs-source-dirs: benchmarks
+  build-depends: base, drinkery, criterion
+  default-language:    Haskell2010
+
+source-repository head
+  type:     git
+  location: https://github.com/fumieval/drinkery
diff --git a/src/Data/Drinkery.hs b/src/Data/Drinkery.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Drinkery.hs
@@ -0,0 +1,11 @@
+module Data.Drinkery
+    ( module Data.Drinkery.Class
+    , module Data.Drinkery.Distiller
+    , module Data.Drinkery.Tap
+    , Patron(..)
+    )where
+
+import Data.Drinkery.Boozer
+import Data.Drinkery.Class
+import Data.Drinkery.Distiller
+import Data.Drinkery.Tap
diff --git a/src/Data/Drinkery/Boozer.hs b/src/Data/Drinkery/Boozer.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Drinkery/Boozer.hs
@@ -0,0 +1,137 @@
+{-# LANGUAGE Rank2Types, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-}
+{-# LANGUAGE DeriveFunctor #-}
+-----------------------------------------------------------------------
+--
+-- Module      :  Data.Drinkery.Boozer
+-- Copyright   :  (c) Fumiaki Kinoshita 2017
+-- License     :  BSD3
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+--
+-- Basic consumer
+-----------------------------------------------------------------------
+module Data.Drinkery.Boozer where
+
+import Control.Monad.Trans.Class
+import Control.Monad.IO.Class
+import Control.Monad
+import Control.Monad.Reader.Class
+import Control.Monad.State.Class
+import Data.Drinkery.Class
+
+-- | Boozer is the initial encoding of a consumer.
+data Boozer r s m a = Drink (s -> Boozer r s m a)
+  | Spit s (Boozer r s m a)
+  | Call r (Boozer r s m a)
+  | Lift (m (Boozer r s m a))
+  | Pure a
+  deriving Functor
+
+-- | Tear down a 'Boozer', maintaining a stack of leftovers.
+iterBoozer :: ([s] -> a -> z) -- ^ return
+  -> ((s -> z) -> z) -- ^ drink
+  -> (r -> z -> z) -- ^ call
+  -> (forall x. m x -> (x -> z) -> z) -- ^ bind
+  -> Boozer r s m a -> z
+iterBoozer p d c t = go [] where
+  go [] (Drink k) = d (go [] . k)
+  go (x : xs) (Drink k) = go xs (k x)
+  go xs (Spit s k) = go (s : xs) k
+  go xs (Call r k) = c r (go xs k)
+  go xs (Lift m) = t m (go xs)
+  go xs (Pure a) = p xs a
+
+hoistBoozer :: Functor n => (forall x. m x -> n x) -> Boozer r s m a -> Boozer r s n a
+hoistBoozer t = go where
+  go (Pure a) = Pure a
+  go (Lift m) = Lift $ go <$> t m
+  go (Call r k) = Call r (go k)
+  go (Spit s k) = Spit s (go k)
+  go (Drink f) = Drink $ go . f
+
+instance Functor m => Applicative (Boozer r s m) where
+  pure = Pure
+  {-# INLINE pure #-}
+  (<*>) = ap
+  (*>) = (>>)
+
+instance Functor m => Monad (Boozer r s m) where
+  return = Pure
+  {-# INLINE return #-}
+  m0 >>= k = go m0 where
+    go (Pure a) = k a
+    go (Drink m) = Drink $ go . m
+    go (Lift m) = Lift $ fmap go m
+    go (Call r c) = Call r (go c)
+    go (Spit s c) = Spit s (go c)
+
+  m0 >> k = go m0 where
+    go (Pure _) = k
+    go (Drink m) = Drink $ go . m
+    go (Lift m) = Lift $ fmap go m
+    go (Call r c) = Call r (go c)
+    go (Spit s c) = Spit s (go c)
+
+instance MonadTrans (Boozer r s) where
+  lift m = Lift $ Pure <$> m
+
+instance MonadIO m => MonadIO (Boozer r s m) where
+  liftIO m = Lift $ Pure <$> liftIO m
+
+instance MonadReader x m => MonadReader x (Boozer r s m) where
+  ask = lift ask
+  local f = hoistBoozer (local f)
+
+instance MonadState x m => MonadState x (Boozer r s m) where
+  get = lift get
+  put = lift . put
+  state = lift . state
+
+instance Functor m => MonadDrunk r s (Boozer r s m) where
+  drink = Drink Pure
+  spit s = Spit s (Pure ())
+  call r = Call r (Pure ())
+
+-- | 'Patron' is a CPS'd 'Boozer'.
+newtype Patron r s m a = Patron
+  { unPatron :: forall x. (a -> Boozer r s m x) -> Boozer r s m x }
+
+runPatron :: Patron r s m a -> Boozer r s m a
+runPatron m = unPatron m Pure
+{-# INLINE runPatron #-}
+
+instance Functor (Patron r s m) where
+  fmap f m = Patron $ \cont -> unPatron m $ cont . f
+  {-# INLINE fmap #-}
+
+instance Applicative (Patron r s m) where
+  pure a = Patron $ \cont -> cont a
+  {-# INLINE pure #-}
+  (<*>) = ap
+  {-# INLINE (<*>) #-}
+  (*>) = (>>)
+  {-# INLINE (*>) #-}
+
+instance Monad (Patron r s m) where
+  return a = Patron ($a)
+  Patron m >>= k = Patron $ \cont -> m (\a -> unPatron (k a) cont)
+
+instance MonadTrans (Patron r s) where
+  lift m = Patron $ \cont -> Lift $ cont <$> m
+
+instance MonadDrunk r s (Patron r s m) where
+  drink = Patron $ \cont -> Drink cont
+  spit s = Patron $ \cont -> Spit s $ cont ()
+  call r = Patron $ \cont -> Call r $ cont ()
+
+instance MonadReader x m => MonadReader x (Patron r s m) where
+  ask = lift ask
+  local f m = Patron $ \cont -> unPatron m (local f . cont)
+
+instance MonadState x m => MonadState x (Patron r s m) where
+  get = lift get
+  put = lift . put
+  state = lift . state
+
+instance MonadIO m => MonadIO (Patron r s m) where
+  liftIO m = Patron $ \cont -> Lift $ cont <$> liftIO m
diff --git a/src/Data/Drinkery/Class.hs b/src/Data/Drinkery/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Drinkery/Class.hs
@@ -0,0 +1,91 @@
+{-# LANGUAGE Rank2Types, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances, UndecidableInstances #-}
+{-# LANGUAGE DeriveFunctor #-}
+-----------------------------------------------------------------------
+--
+-- Module      :  Data.Drinkery.Class
+-- Copyright   :  (c) Fumiaki Kinoshita 2017
+-- License     :  BSD3
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+--
+-- Basic classes
+-----------------------------------------------------------------------
+module Data.Drinkery.Class where
+
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.Cont
+import Control.Monad.Trans.Maybe
+import qualified Control.Monad.Trans.Reader as Reader
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict
+import qualified Control.Monad.Trans.RWS.Lazy as Lazy
+import qualified Control.Monad.Trans.RWS.Strict as Strict
+
+class Monad m => MonadDrunk r s m | m -> r s where
+  drink :: m s
+  spit :: s -> m ()
+  call :: r -> m ()
+
+instance MonadDrunk r s m => MonadDrunk r s (Reader.ReaderT x m) where
+  drink = lift drink
+  spit = lift . spit
+  call = lift . call
+
+instance MonadDrunk r s m => MonadDrunk r s (Lazy.StateT x m) where
+  drink = lift drink
+  spit = lift . spit
+  call = lift . call
+
+instance MonadDrunk r s m => MonadDrunk r s (Strict.StateT x m) where
+  drink = lift drink
+  spit = lift . spit
+  call = lift . call
+
+instance (Monoid x, MonadDrunk r s m) => MonadDrunk r s (Lazy.WriterT x m) where
+  drink = lift drink
+  spit = lift . spit
+  call = lift . call
+
+instance (Monoid x, MonadDrunk r s m) => MonadDrunk r s (Strict.WriterT x m) where
+  drink = lift drink
+  spit = lift . spit
+  call = lift . call
+
+instance (Monoid y, MonadDrunk r s m) => MonadDrunk r s (Lazy.RWST x y z m) where
+  drink = lift drink
+  spit = lift . spit
+  call = lift . call
+
+instance (Monoid y, MonadDrunk r s m) => MonadDrunk r s (Strict.RWST x y z m) where
+  drink = lift drink
+  spit = lift . spit
+  call = lift . call
+
+instance MonadDrunk r s m => MonadDrunk r s (MaybeT m) where
+  drink = lift drink
+  spit = lift . spit
+  call = lift . call
+
+instance MonadDrunk r s m => MonadDrunk r s (ContT x m) where
+  drink = lift drink
+  spit = lift . spit
+  call = lift . call
+
+-- | Get one element without consuming.
+smell :: MonadDrunk r s m => m s
+smell = do
+  s <- drink
+  spit s
+  return s
+
+class CloseRequest a where
+  -- | A value representing a close request
+  closeRequest :: a
+
+instance CloseRequest () where
+  closeRequest = ()
+
+instance CloseRequest a => CloseRequest [a] where
+  closeRequest = [closeRequest]
diff --git a/src/Data/Drinkery/Distiller.hs b/src/Data/Drinkery/Distiller.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Drinkery/Distiller.hs
@@ -0,0 +1,172 @@
+{-# LANGUAGE Rank2Types, BangPatterns, LambdaCase, FlexibleContexts #-}
+-----------------------------------------------------------------------
+--
+-- Module      :  Data.Drinkery.Distiller
+-- Copyright   :  (c) Fumiaki Kinoshita 2017
+-- License     :  BSD3
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+--
+-- Stream transducers
+-----------------------------------------------------------------------
+module Data.Drinkery.Distiller
+  ( Distiller
+  -- * Special combinators
+  , (+&)
+  , ($&)
+  -- * Attaching a distiller
+  , (++$)
+  , ($$$)
+  -- * Patron
+  , (++&)
+  , ($$&)
+  -- * Stock distillers
+  , mapping
+  , traversing
+  , filtering
+  , scanning
+  , scanningMaybe
+  , throughMaybe
+  -- * Internal
+  , boozeOn
+  , distillWith
+  ) where
+
+import Control.Monad.Trans.Class
+import Data.Drinkery.Tap
+import Data.Drinkery.Class
+import Data.Drinkery.Boozer
+
+boozeOn :: (Monoid r, Monad m) => (forall x. n x -> m x)
+  -> (r -> [s] -> Tap m r s -> a -> m z)
+  -> r -> [s] -> Tap m r s
+  -> Boozer r s n a
+  -> m z
+boozeOn t cont = go where
+  go !r [] (Tap f) (Drink k) = f r >>= \(s, b) -> go mempty [] b (k s)
+  go !r (s : ss) b (Drink f) = go r ss b (f s)
+  go !r ss b (Spit s k) = go r (s : ss) b k
+  go !r ss b (Call r' k) = go (mappend r r') ss b k
+  go !r ss b (Lift m) = t m >>= go r ss b
+  go !r ss b (Pure a) = cont r ss b a
+{-# INLINE boozeOn #-}
+
+-- | 'Distiller p q m r s' is a stream transducer which has five parameters:
+--
+-- * @p@ request to the upstream
+-- * @q@ input
+-- * @m@ underlying monad
+-- * @r@ request from the downstream
+-- * @s@ output
+type Distiller p q m = Tap (Patron p q m)
+
+distillWith :: (Monoid p, Monad m) => (forall x. n x -> m x) -> Tap m p q -> Distiller p q n r s -> Tap m r s
+distillWith trans = go mempty [] where
+  go r lo b (Tap m) = Tap $ \rs -> boozeOn trans
+    (\r' lo' b' (s, cont) -> pure (s, go r' lo' b' cont))
+    r lo b (runPatron (m rs))
+{-# INLINE distillWith #-}
+
+infix 6 +&
+infixr 7 $&
+infix 6 ++&
+infixl 7 ++$
+infixr 7 $$&
+infixl 8 $$$
+
+-- | Connect a tap with a patron.
+--
+-- Mnemonic:
+--
+-- * @+@ Left operand is a tap.
+-- * @+@ Returns a tap (along with the result).
+-- * @&@ Right operand is a patron.
+(++&) :: (Monoid r, Monad m) => Tap m r s -> Patron r s m a -> m (Tap m r s, a)
+t ++& p = boozeOn id (\r s t' a -> pure (orderTap r $ foldr consTap t' s, a)) mempty [] t (runPatron p)
+{-# INLINE (++&) #-}
+
+-- | Attach a distiller to a tap.
+--
+-- Mnemonic:
+--
+-- * @+@ Left operand is a tap.
+-- * @+@ Returns a tap.
+-- * @$@ Right operand is a distiller.
+(++$) :: (Monoid p, Monad m) => Tap m p q -> Distiller p q m r s -> Tap m r s
+(++$) = distillWith id
+{-# INLINE (++$) #-}
+
+-- | Full duplex composition of distillers.
+--
+-- Mnemonic:
+--
+-- * @$@ Left operand is a distiller.
+-- * @$@ Returns a distiller.
+-- * @$@ Right operand is a distiller.
+($$$) :: (Monoid r, Monad m) => Distiller p q m r s -> Distiller r s m t u -> Distiller p q m t u
+($$$) = distillWith lift
+{-# INLINE ($$$) #-}
+
+-- | Attach a distiller to a patron.
+--
+-- Mnemonic:
+--
+-- * @$@ Left operand is a distiller.
+-- * @$@ Returns the used distiller.
+-- * @&@ Right operand is a patron.
+($$&) :: (Monoid r, Monad m) => Distiller p q m r s -> Patron r s m a
+  -> Patron p q m (Distiller p q m r s, a)
+d $$& b = boozeOn lift (\r s t a -> pure (orderTap r $ foldr consTap t s, a)) mempty [] d (runPatron b)
+{-# INLINE ($$&) #-}
+
+-- | Connect a tap with a patron and close the used tap.
+(+&) :: (Monoid r, CloseRequest r, Monad m) => Tap m r s -> Patron r s m a -> m a
+t +& b = do
+  (t', a) <- t ++& b
+  _ <- unTap t' closeRequest
+  return a
+{-# INLINE (+&) #-}
+
+-- | Like '$&&' but discards the used distiller.
+($&) :: (Monoid r, Monad m) => Distiller p q m r s -> Patron r s m a -> Patron p q m a
+t $& b = fmap snd $ t $$& b
+{-# INLINE ($&) #-}
+
+-- | Create a request-preserving distiller.
+propagating :: Functor m => Patron r a m (b, Distiller r a m r b) -> Distiller r a m r b
+propagating m = Tap $ \r -> call r >> m
+{-# INLINE propagating #-}
+
+mapping :: Functor m => (a -> b) -> Distiller r a m r b
+mapping f = propagating $ drink >>= \a -> return (f a, mapping f)
+
+traversing :: Monad m => (a -> m b) -> Distiller r a m r b
+traversing f = propagating $ drink >>= \a -> lift (f a) >>= \b -> return (b, traversing f)
+
+filtering :: (Monoid r, Functor m) => (a -> Bool) -> Distiller r a m r a
+filtering f = propagating $ drink >>= \a -> if f a
+  then return (a, filtering f)
+  else unTap (filtering f) mempty
+
+scanning :: (Monoid r, Functor m) => (b -> a -> b) -> b -> Distiller r a m r b
+scanning f b0 = consTap b0 $ go b0 where
+  go b = propagating $ fmap (\a -> let !b' = f b a in (b', go $ b')) drink
+{-# INLINE scanning #-}
+
+scanningMaybe :: (Monoid r, Functor m) => (b -> a -> b) -> b -> Distiller r (Maybe a) m r (Maybe b)
+scanningMaybe f b0 = consTap (Just b0) $ go b0 where
+  go b = Tap $ \r -> Patron $ \cont -> Call r $ Drink $ \case
+    Just a -> let !b' = f b a in cont (Just b', go b')
+    Nothing -> cont (Nothing, go b)
+{-# INLINE scanningMaybe #-}
+
+-- | Transform a 'Distiller' to operate on a stream of 'Maybe's.
+throughMaybe :: (Monoid r, Monad m) => Distiller p q m r s -> Distiller p (Maybe q) m r (Maybe s)
+throughMaybe d = Tap $ \rs -> iterBoozer
+  (\qs (s, d') -> (Just s, throughMaybe d') <$ mapM_ (spit . Just) qs)
+  (\cont -> drink >>= maybe (pure end) cont)
+  (\p cont -> call p >> cont)
+  ((>>=) . lift)
+  $ runPatron $ unTap d rs
+  where
+    end = (Nothing, throughMaybe d)
diff --git a/src/Data/Drinkery/Glass.hs b/src/Data/Drinkery/Glass.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Drinkery/Glass.hs
@@ -0,0 +1,71 @@
+{-# LANGUAGE LambdaCase #-}
+-----------------------------------------------------------------------
+--
+-- Module      :  Data.Drinkery.Glass
+-- Copyright   :  (c) Fumiaki Kinoshita 2017
+-- License     :  BSD3
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+--
+-- Things to work with finite streams
+-----------------------------------------------------------------------
+module Data.Drinkery.Glass
+  ( eof
+  , runBarman
+  , runSommelier
+  , pour
+  -- * 'MonadDrunk' actions
+  , foldl'
+  , foldM
+  , traverse_
+  , sinkNull
+  )
+where
+
+import Control.Applicative
+import Control.Monad hiding (foldM)
+import Data.Drinkery.Class
+import Data.Drinkery.Tap
+import qualified Data.Foldable as F
+
+-- | End of stream
+eof :: (Applicative m, Alternative f) => Tap m r (f a)
+eof = Tap $ const $ pure (empty, eof)
+
+-- | Run a 'Barman' action and terminate the stream with 'eof'.
+runBarman :: (Monoid r, Applicative m, Alternative f) => Barman r (f s) m a -> Tap m r (f s)
+runBarman m = unBarman m (const eof)
+{-# INLINE runBarman #-}
+
+-- | Run 'Sommelier' and terminate the stream with 'eof'.
+runSommelier :: (Monoid r, Applicative m, Alternative f) => Sommelier r m s -> Tap m r (f s)
+runSommelier m = unSommelier m (consTap . pure) eof
+{-# INLINE runSommelier #-}
+
+pour :: (Monoid r, Applicative f, Applicative m) => s -> Barman r (f s) m ()
+pour = topup . pure
+
+foldl' :: (Foldable t, MonadDrunk r (t a) m) => (b -> a -> b) -> b -> m b
+foldl' f = go where
+  go b = do
+    t <- drink
+    if null t
+      then return b
+      else go $! F.foldl' f b t
+
+foldM :: (Foldable t, MonadDrunk r (t a) m) => (b -> a -> m b) -> b -> m b
+foldM f = go where
+  go b = do
+    t <- drink
+    if null t
+      then return b
+      else F.foldlM f b t >>= go
+
+traverse_ :: (Foldable t, MonadDrunk r (t a) m) => (a -> m b) -> m ()
+traverse_ f = go where
+  go = do
+    t <- drink
+    if null t then return () else F.traverse_ f t >> go
+
+sinkNull :: (Foldable t, MonadDrunk r (t a) m) => m ()
+sinkNull = drink >>= \t -> unless (null t) sinkNull
diff --git a/src/Data/Drinkery/Tap.hs b/src/Data/Drinkery/Tap.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Drinkery/Tap.hs
@@ -0,0 +1,124 @@
+{-# LANGUAGE Rank2Types, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances #-}
+-----------------------------------------------------------------------
+--
+-- Module      :  Data.Drinkery.Tap
+-- Copyright   :  (c) Fumiaki Kinoshita 2017
+-- License     :  BSD3
+--
+-- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
+--
+-- Stream producers
+-----------------------------------------------------------------------
+module Data.Drinkery.Tap (
+  Tap(..)
+  , consTap
+  , orderTap
+  , makeTap
+  , Barman(..)
+  , topup
+  , accept
+  , inexhaustible
+  , Sommelier(..)
+  , taste
+  , inquire
+) where
+
+import Control.Applicative
+import Control.Monad
+import Control.Monad.IO.Class
+import Control.Monad.Trans.Class
+import Data.Drinkery.Class
+
+-- | @'Tap' m r s@ is a non-monadic, endless producer of @s@. It takes a request
+-- @r@.
+newtype Tap m r s = Tap { unTap :: r -> m (s, Tap m r s) }
+
+-- | Prepend a new element, delaying requests.
+consTap :: (Monoid r, Applicative m) => s -> Tap m r s -> Tap m r s
+consTap s t = Tap $ \r -> pure (s, Tap $ unTap t . mappend r)
+{-# INLINE consTap #-}
+
+-- | Send a request to a 'Tap'.
+orderTap :: (Monoid r) => r -> Tap m r s -> Tap m r s
+orderTap r t = Tap $ \r' -> unTap t $! mappend r r'
+{-# INLINE orderTap #-}
+
+-- | Involve an action.
+makeTap :: (Monoid r, Monad m) => m (Tap m r s) -> Tap m r s
+makeTap m = Tap $ \r -> m >>= \t -> unTap t r
+{-# INLINE makeTap #-}
+
+-- | Monadic producer
+newtype Barman r s m a = Barman { unBarman :: (a -> Tap m r s) -> Tap m r s }
+
+instance Functor (Barman r s m) where
+  fmap = liftM
+
+instance Applicative (Barman r s m) where
+  pure = return
+  (<*>) = ap
+
+instance Monad (Barman r s m) where
+  return a = Barman ($ a)
+  Barman m >>= k = Barman $ \cont -> m $ \a -> unBarman (k a) cont
+
+instance MonadTrans (Barman r s) where
+  lift m = Barman $ \k -> Tap $ \rs -> m >>= \a -> unTap (k a) rs
+
+instance MonadDrunk r s m => MonadDrunk r s (Barman p q m) where
+  drink = lift drink
+  spit = lift . spit
+  call = lift . call
+
+-- | Produce one element. Orders are put off.
+topup :: (Monoid r, Applicative m) => s -> Barman r s m ()
+topup s = Barman $ \cont -> consTap s (cont ())
+
+-- | Accept orders and clear the queue.
+accept :: Monoid r => Barman r s m r
+accept = Barman $ \cont -> Tap $ \rs -> unTap (cont rs) mempty
+
+-- | Create a infinite 'Tap' from a 'Barman'.
+--
+-- @Barman r s (Boozer p q m) x -> Distiller p q m r s@
+--
+inexhaustible :: Barman r s m x -> Tap m r s
+inexhaustible t = unBarman t $ const $ inexhaustible t
+
+-- | Backtracking producer a.k.a. "ListT done right".
+newtype Sommelier r m s = Sommelier
+  { unSommelier :: forall x. (s -> Tap m r x -> Tap m r x) -> Tap m r x -> Tap m r x }
+
+instance Functor (Sommelier r m) where
+  fmap f m = Sommelier $ \c e -> unSommelier m (c . f) e
+
+instance Applicative (Sommelier r m) where
+  pure = return
+  (<*>) = ap
+
+instance Monad (Sommelier r m) where
+  return s = Sommelier $ \c e -> c s e
+  m >>= k = Sommelier $ \c e -> unSommelier m (\s -> unSommelier (k s) c) e
+
+instance Alternative (Sommelier r m) where
+  empty = Sommelier $ \_ e -> e
+  a <|> b = Sommelier $ \c e -> unSommelier a c (unSommelier b c e)
+
+instance MonadTrans (Sommelier r) where
+  lift m = Sommelier $ \c e -> Tap $ \rs -> m >>= \a -> unTap (c a e) rs
+
+instance MonadIO m => MonadIO (Sommelier r m) where
+  liftIO m = Sommelier $ \c e -> Tap $ \rs -> liftIO m >>= \a -> unTap (c a e) rs
+
+instance MonadDrunk r s m => MonadDrunk r s (Sommelier p m) where
+  drink = lift drink
+  spit = lift . spit
+  call = lift . call
+
+-- | Take all the elements in a 'Foldable' container.
+taste :: Foldable f => f s -> Sommelier r m s
+taste xs = Sommelier $ \c e -> foldr c e xs
+
+-- | Get a request.
+inquire :: Monoid r => Sommelier r m r
+inquire = Sommelier $ \c e -> Tap $ \rs -> unTap (c rs e) mempty
