{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE UndecidableInstances #-}
module Piped.Internal
(
Pipe(..)
, await
, yield
, runPipe
, leftover
, Await(..)
, Yield(..)
, Await'
, Yield'
, runAwait
, runYield
, termLeft
, termRight
, voidRight
, addLeftover
, Void
, fix1
, fix2
) where
import Data.Void
import Control.Monad
import Control.Monad.Reader
import Control.Monad.State
newtype Await i m a = Await { unAwait :: Await' i m a }
data Yield i m a = Yield
{ terminate :: m a
, unYield :: Yield' i m a
}
type Await' i m a = Yield i m a -> m a
type Yield' i m a = i -> Await i m a -> m a
runAwait :: Await i m a -> m a -> Yield' i m a -> m a
runAwait (Await awt) a yld = awt $ Yield a yld
{-# INLINE runAwait #-}
runYield :: Yield i m a -> i -> Await' i m a -> m a
runYield (Yield _ a) i = a i . Await
{-# INLINE runYield #-}
termLeft :: Await i m a
termLeft = Await terminate
{-# INLINE termLeft #-}
termRight :: Yield i1 m a -> Yield i2 m a
termRight r = Yield (terminate r) (\_ _ -> terminate r)
{-# INLINE termRight #-}
voidRight :: Yield Void m a
voidRight = Yield (error "Void") (\i _ -> absurd i)
{-# INLINE voidRight #-}
addLeftover :: i -> Await i m a -> Await i m a
addLeftover i await = Await $ \y -> unYield y i await
newtype Pipe i o m a =
Pipe { unPipe :: forall r. (Await i m r -> Yield o m r -> a -> m r) -> Await i m r -> Yield o m r -> m r }
instance Monad m => Functor (Pipe i o m) where
fmap f (Pipe p) = Pipe $
\rest l r -> p (\l r -> rest l r . f) l r
instance Monad m => Applicative (Pipe i o m) where
pure = return
(<*>) = ap
instance Monad m => Monad (Pipe i o m) where
return x = Pipe $ \f l r -> f l r x
Pipe f >>= g = Pipe $
\rest -> f (\l r a -> unPipe (g a) rest l r)
instance MonadTrans (Pipe i o) where
lift mf = Pipe $ \f l r -> mf >>= f l r
instance MonadIO m => MonadIO (Pipe i o m) where
liftIO = lift . liftIO
instance MonadReader r m => MonadReader r (Pipe i o m) where
ask = lift ask
local f (Pipe p) = Pipe $ \rest l r -> local f $ p rest l r
instance MonadState s m => MonadState s (Pipe i o m) where
get = lift get
put = lift . put
instance Monad m => Semigroup (Pipe i o m a) where
(<>) = (>>)
instance Monad m => Monoid (Pipe i o m ()) where
mempty = pure ()
await :: Monad m => Pipe i o m (Maybe i)
await = Pipe $
\rest l r ->
let term = rest termLeft r Nothing
in runAwait l term $ \i l -> rest l r $ Just i
{-# INLINE await #-}
yield :: o -> Pipe i o m ()
yield i = Pipe $
\rest a y -> runYield y i $ \y -> rest a y ()
{-# INLINE yield #-}
runPipe :: Monad m => Pipe () Void m r -> m r
runPipe pipe = unPipe pipe (\_ _ -> pure) termLeft voidRight
{-# INLINE runPipe #-}
leftover :: i -> Pipe i o m ()
leftover i = Pipe $
\rest l r -> rest (addLeftover i l) r ()
{-# INLINE leftover #-}
fix1 :: a -> ((a -> b) -> a -> b) -> b
fix1 a f = fix f a
{-# INLINE fix1 #-}
fix2 :: a -> b -> ((a -> b -> c) -> a -> b -> c) -> c
fix2 a b f = fix f a b
{-# INLINE fix2 #-}