{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
module Box.Box
( Box (..),
bmap,
hoistb,
glue,
glue_,
glueb,
fuse,
dotb,
Divap(..),
DecAlt(..),
)
where
import Box.Committer
import Box.Emitter
import Data.Functor.Contravariant
import Data.Profunctor
import NumHask.Prelude
import Data.Functor.Contravariant.Divisible
data Box m c e
= Box
{ committer :: Committer m c,
emitter :: Emitter m e
}
hoistb :: Monad m => (forall a. m a -> n a) -> Box m c e -> Box n c e
hoistb nat (Box c e) = Box (hoist nat c) (hoist nat e)
instance (Functor m) => Profunctor (Box m) where
dimap f g (Box c e) = Box (contramap f c) (fmap g e)
instance (Alternative m, Monad m) => Semigroup (Box m c e) where
(<>) (Box c e) (Box c' e') = Box (c <> c') (e <> e')
instance (Alternative m, Monad m) => Monoid (Box m c e) where
mempty = Box mempty mempty
mappend = (<>)
bmap :: (Monad m) => (a' -> m (Maybe a)) -> (b -> m (Maybe b')) -> Box m a b -> Box m a' b'
bmap fc fe (Box c e) = Box (mapC fc c) (mapE fe e)
dotb :: (Monad m) => Box m a b -> Box m b c -> m (Box m a c)
dotb (Box c e) (Box c' e') = glue c' e *> pure (Box c e')
glue :: (Monad m) => Committer m a -> Emitter m a -> m ()
glue c e = go
where
go = do
a <- emit e
c' <- maybe (pure False) (commit c) a
when c' go
glue_ :: (Monad m) => Committer m a -> Emitter m a -> m ()
glue_ c e = go
where
go = do
a <- emit e
case a of
Nothing -> go
Just a' -> do
b <- commit c a'
case b of
True -> go
False -> pure ()
glueb :: (Monad m) => Box m a a -> m ()
glueb (Box c e) = glue c e
fuse :: (Monad m) => (a -> m (Maybe b)) -> Box m b a -> m ()
fuse f (Box c e) = glue c (mapE f e)
class Divap p where
divap :: (a -> (b, c)) -> ((d, e) -> f) -> p b d -> p c e -> p a f
conpur :: a -> p b a
class Profunctor p => DecAlt p where
choice :: (a -> Either b c) -> (Either d e -> f) -> p b d -> p c e -> p a f
loss :: p Void b
instance (Applicative m) => Divap (Box m) where
divap split merge (Box lc le) (Box rc re) = Box (divide split lc rc) (liftA2 (curry merge) le re)
conpur a = Box conquer (pure a)
instance (Monad m, Alternative m) => DecAlt (Box m) where
choice split merge (Box lc le) (Box rc re) =
Box (choose split lc rc) (fmap merge $ (fmap Left le) <|> (fmap Right re))
loss = Box (lose absurd) empty