module Data.Drinkery.Tap (
Tap(..)
, consTap
, orderTap
, makeTap
, repeatTap
, repeatTapM
, repeatTapM'
, Joint(..)
, Barman(..)
, yield
, accept
, inexhaustible
, runBarman
, runBarman'
, pour
, Sommelier(..)
, taste
, inquire
, runSommelier
, runSommelier'
, retractSommelier
, drink
, leftover
, request
, smell
, eof
) where
import Control.Applicative
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Data.Semigroup
import Data.Drinkery.Class
newtype Tap r s m = Tap { unTap :: r -> m (s, Tap r s m) }
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)
orderTap :: (Semigroup r) => r -> Tap r s m -> Tap r s m
orderTap r t = Tap $ \r' -> unTap t $! r <> r'
makeTap :: (Monad m) => m (Tap r s m) -> Tap r s m
makeTap m = Tap $ \r -> m >>= \t -> unTap t r
repeatTap :: Applicative m => s -> Tap r s m
repeatTap s = go where
go = Tap $ const $ pure (s, go)
repeatTapM :: Applicative m => m s -> Tap r s m
repeatTapM m = go where
go = Tap $ const $ flip (,) go <$> m
repeatTapM' :: Applicative m => m s -> Tap () s m
repeatTapM' = repeatTapM
instance CloseRequest r => Closable (Tap r s) where
close t = void $ unTap t closeRequest
drink :: (Monoid r, MonadDrunk (Tap r s) m) => m s
drink = drinking $ \t -> unTap t mempty
leftover :: (Semigroup r, MonadDrunk (Tap r s) m) => s -> m ()
leftover s = drinking $ \t -> return ((), consTap s t)
request :: (Semigroup r, MonadDrunk (Tap r s) m) => r -> m ()
request r = drinking $ \t -> return ((), orderTap r t)
smell :: (Monoid r, Semigroup r, MonadDrunk (Tap r s) m) => m s
smell = do
s <- drink
leftover s
return s
newtype Joint r m s = Joint { unJoint :: Tap r s m }
instance Functor m => Functor (Joint r m) where
fmap f (Joint tap0) = Joint (go tap0) where
go tap = Tap $ \r -> fmap (\(s, t) -> (f s, go t)) $ unTap tap r
instance Applicative m => Applicative (Joint r m) where
pure = Joint . repeatTap
Joint tapF <*> Joint tapA = Joint (go tapF tapA) where
go s t = Tap $ \r -> (\(f, s') (x, t') -> (f x, go s' t'))
<$> unTap s r
<*> unTap t r
newtype Barman r s m a = Barman { unBarman :: (a -> Tap r s m) -> Tap r s m }
instance Functor (Barman r s m) where
fmap f (Barman m) = Barman $ \cont -> m (cont . f)
instance Applicative (Barman r s m) where
pure = return
Barman m <*> Barman k = Barman $ \cont -> m $ \f -> k $ cont . f
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 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)
pour :: (Semigroup r, Applicative m) => s -> Barman r s m ()
pour s = Barman $ \cont -> consTap s (cont ())
accept :: Monoid r => Barman r s m r
accept = Barman $ \cont -> Tap $ \rs -> unTap (cont rs) mempty
inexhaustible :: Barman r s m x -> Tap r s m
inexhaustible t = go where
go = unBarman t $ const go
newtype Sommelier r m s = Sommelier
{ unSommelier :: forall x. (s -> Tap r x m -> Tap r x m) -> Tap r x m -> Tap r x m }
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 MonadPlus (Sommelier r m) where
mzero = empty
mplus = (<|>)
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 t m => MonadDrunk t (Sommelier p m) where
drinking f = lift (drinking f)
taste :: Foldable f => f s -> Sommelier r m s
taste xs = Sommelier $ \c e -> foldr c e xs
inquire :: Monoid r => Sommelier r m r
inquire = Sommelier $ \c e -> Tap $ \rs -> unTap (c rs e) mempty
eof :: (Applicative m, Alternative f) => Tap r (f a) m
eof = repeatTap empty
runBarman :: (Monoid r, Applicative m, Alternative f) => Barman r (f s) m a -> Tap r (f s) m
runBarman m = unBarman m (const eof)
runBarman' :: (Applicative m, Alternative f) => Barman () (f s) m a -> Tap () (f s) m
runBarman' = runBarman
runSommelier :: (Semigroup r, Applicative m, Alternative f) => Sommelier r m s -> Tap r (f s) m
runSommelier m = unSommelier m (consTap . pure) eof
runSommelier' :: (Applicative m, Alternative f) => Sommelier () m s -> Tap () (f s) m
runSommelier' = runSommelier
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)
yield :: (Semigroup r, Applicative f, Applicative m) => s -> Barman r (f s) m ()
yield = pour . pure