{-# LANGUAGE DerivingVia #-}

{- | Often, we want to work with automata that don't produce exactly one output per input.
In these situations, 'FilterAutomaton' is a good abstraction.

For example, we might want to filter out certain values at some point, and only work with the remaining ones from there on.
So for each input, the automaton will either output a value, or it will not output a value.
A simple ad hoc solution is to create an automaton of type @'Automaton' m a ('Maybe' b)@,
where 'Nothing' encodes the absence of a value.
When composing a longer chain of such filtering automata, it often gets tedious to join all of the 'Maybe' layers.
'FilterAutomaton' abstracts this.

Instead of locking into the concrete 'Maybe' type, a more general API based on well-established type classes such as 'Witherable' was chosen.
As a result, it can be used with a custom type encoding optionality,
and even generalised to situations where you might have several outputs per input, using e.g. the list monad.
-}
module Data.Automaton.Filter where

-- base
import Control.Applicative (Alternative (..))
import Control.Arrow
import Control.Category (Category (..))
import Control.Monad (join)
import Data.Functor ((<&>))
import Data.Functor.Compose (Compose (..))
import Prelude hiding (filter, id, (.))

-- transformers
import Control.Monad.Trans.Reader (ReaderT (..))

-- profunctors
import Data.Profunctor (Choice (..), Profunctor (..), Strong (..))
import Data.Profunctor.Choice (Cochoice (..))
import Data.Profunctor.Traversing (Traversing (..))

-- witherable
import Witherable (Filterable (..))

-- semialign
import Data.Align (Align (..), Semialign)
import Data.Semialign (Semialign (..))

-- automaton
import Data.Automaton
import Data.Stream (hoist')
import Data.Stream.Filter (FilterStream (..), streamFilter)
import Data.Stream.Optimized (OptimizedStreamT (Stateful))

{- | An automaton that filters or traverses its output using a type operator @f@.

When @f@ is 'Maybe', then @'FilterAutomaton' 'Maybe' a b@ can filter in the sense that not every input necessarily leads to an output.

@f@ can also be a type that allows multiple positions, such as lists, or 'NonEmpty'.
In this case, 'FilterAutomaton' branches out and can explore multiple outputs at the same time.
(It keeps a single state, though.)
-}
newtype FilterAutomaton m f a b = FilterAutomaton
  { forall (m :: Type -> Type) (f :: Type -> Type) a b.
FilterAutomaton m f a b -> Automaton m a (f b)
getFilterAutomaton :: Automaton m a (f b)
  -- ^ Interpret a 'FilterAutomaton'.
  --   For instance if @f = 'Maybe'@, the resulting automaton will output 'Nothing' whenever there is no output of the 'FilterAutomaton'.
  }
  deriving ((forall a b.
 (a -> b) -> FilterAutomaton m f a a -> FilterAutomaton m f a b)
-> (forall a b.
    a -> FilterAutomaton m f a b -> FilterAutomaton m f a a)
-> Functor (FilterAutomaton m f a)
forall a b. a -> FilterAutomaton m f a b -> FilterAutomaton m f a a
forall a b.
(a -> b) -> FilterAutomaton m f a a -> FilterAutomaton m f a b
forall (f :: Type -> Type).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
forall (m :: Type -> Type) a (f :: Type -> Type) a b.
(Functor m, Functor f) =>
a -> FilterAutomaton m f a b -> FilterAutomaton m f a a
forall (m :: Type -> Type) a (f :: Type -> Type) a b.
(Functor m, Functor f) =>
(a -> b) -> FilterAutomaton m f a a -> FilterAutomaton m f a b
$cfmap :: forall (m :: Type -> Type) a (f :: Type -> Type) a b.
(Functor m, Functor f) =>
(a -> b) -> FilterAutomaton m f a a -> FilterAutomaton m f a b
fmap :: forall a b.
(a -> b) -> FilterAutomaton m f a a -> FilterAutomaton m f a b
$c<$ :: forall (m :: Type -> Type) a (f :: Type -> Type) a b.
(Functor m, Functor f) =>
a -> FilterAutomaton m f a b -> FilterAutomaton m f a a
<$ :: forall a b. a -> FilterAutomaton m f a b -> FilterAutomaton m f a a
Functor, Functor (FilterAutomaton m f a)
Functor (FilterAutomaton m f a) =>
(forall a. a -> FilterAutomaton m f a a)
-> (forall a b.
    FilterAutomaton m f a (a -> b)
    -> FilterAutomaton m f a a -> FilterAutomaton m f a b)
-> (forall a b c.
    (a -> b -> c)
    -> FilterAutomaton m f a a
    -> FilterAutomaton m f a b
    -> FilterAutomaton m f a c)
-> (forall a b.
    FilterAutomaton m f a a
    -> FilterAutomaton m f a b -> FilterAutomaton m f a b)
-> (forall a b.
    FilterAutomaton m f a a
    -> FilterAutomaton m f a b -> FilterAutomaton m f a a)
-> Applicative (FilterAutomaton m f a)
forall a. a -> FilterAutomaton m f a a
forall a b.
FilterAutomaton m f a a
-> FilterAutomaton m f a b -> FilterAutomaton m f a a
forall a b.
FilterAutomaton m f a a
-> FilterAutomaton m f a b -> FilterAutomaton m f a b
forall a b.
FilterAutomaton m f a (a -> b)
-> FilterAutomaton m f a a -> FilterAutomaton m f a b
forall a b c.
(a -> b -> c)
-> FilterAutomaton m f a a
-> FilterAutomaton m f a b
-> FilterAutomaton m f a c
forall (f :: Type -> Type).
Functor f =>
(forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
forall (m :: Type -> Type) a (f :: Type -> Type).
(Applicative m, Applicative f) =>
Functor (FilterAutomaton m f a)
forall (m :: Type -> Type) a (f :: Type -> Type) a.
(Applicative m, Applicative f) =>
a -> FilterAutomaton m f a a
forall (m :: Type -> Type) a (f :: Type -> Type) a b.
(Applicative m, Applicative f) =>
FilterAutomaton m f a a
-> FilterAutomaton m f a b -> FilterAutomaton m f a a
forall (m :: Type -> Type) a (f :: Type -> Type) a b.
(Applicative m, Applicative f) =>
FilterAutomaton m f a a
-> FilterAutomaton m f a b -> FilterAutomaton m f a b
forall (m :: Type -> Type) a (f :: Type -> Type) a b.
(Applicative m, Applicative f) =>
FilterAutomaton m f a (a -> b)
-> FilterAutomaton m f a a -> FilterAutomaton m f a b
forall (m :: Type -> Type) a (f :: Type -> Type) a b c.
(Applicative m, Applicative f) =>
(a -> b -> c)
-> FilterAutomaton m f a a
-> FilterAutomaton m f a b
-> FilterAutomaton m f a c
$cpure :: forall (m :: Type -> Type) a (f :: Type -> Type) a.
(Applicative m, Applicative f) =>
a -> FilterAutomaton m f a a
pure :: forall a. a -> FilterAutomaton m f a a
$c<*> :: forall (m :: Type -> Type) a (f :: Type -> Type) a b.
(Applicative m, Applicative f) =>
FilterAutomaton m f a (a -> b)
-> FilterAutomaton m f a a -> FilterAutomaton m f a b
<*> :: forall a b.
FilterAutomaton m f a (a -> b)
-> FilterAutomaton m f a a -> FilterAutomaton m f a b
$cliftA2 :: forall (m :: Type -> Type) a (f :: Type -> Type) a b c.
(Applicative m, Applicative f) =>
(a -> b -> c)
-> FilterAutomaton m f a a
-> FilterAutomaton m f a b
-> FilterAutomaton m f a c
liftA2 :: forall a b c.
(a -> b -> c)
-> FilterAutomaton m f a a
-> FilterAutomaton m f a b
-> FilterAutomaton m f a c
$c*> :: forall (m :: Type -> Type) a (f :: Type -> Type) a b.
(Applicative m, Applicative f) =>
FilterAutomaton m f a a
-> FilterAutomaton m f a b -> FilterAutomaton m f a b
*> :: forall a b.
FilterAutomaton m f a a
-> FilterAutomaton m f a b -> FilterAutomaton m f a b
$c<* :: forall (m :: Type -> Type) a (f :: Type -> Type) a b.
(Applicative m, Applicative f) =>
FilterAutomaton m f a a
-> FilterAutomaton m f a b -> FilterAutomaton m f a a
<* :: forall a b.
FilterAutomaton m f a a
-> FilterAutomaton m f a b -> FilterAutomaton m f a a
Applicative, Applicative (FilterAutomaton m f a)
Applicative (FilterAutomaton m f a) =>
(forall a. FilterAutomaton m f a a)
-> (forall a.
    FilterAutomaton m f a a
    -> FilterAutomaton m f a a -> FilterAutomaton m f a a)
-> (forall a. FilterAutomaton m f a a -> FilterAutomaton m f a [a])
-> (forall a. FilterAutomaton m f a a -> FilterAutomaton m f a [a])
-> Alternative (FilterAutomaton m f a)
forall a. FilterAutomaton m f a a
forall a. FilterAutomaton m f a a -> FilterAutomaton m f a [a]
forall a.
FilterAutomaton m f a a
-> FilterAutomaton m f a a -> FilterAutomaton m f a a
forall (f :: Type -> Type).
Applicative f =>
(forall a. f a)
-> (forall a. f a -> f a -> f a)
-> (forall a. f a -> f [a])
-> (forall a. f a -> f [a])
-> Alternative f
forall (m :: Type -> Type) a (f :: Type -> Type).
(Alternative m, Applicative f) =>
Applicative (FilterAutomaton m f a)
forall (m :: Type -> Type) a (f :: Type -> Type) a.
(Alternative m, Applicative f) =>
FilterAutomaton m f a a
forall (m :: Type -> Type) a (f :: Type -> Type) a.
(Alternative m, Applicative f) =>
FilterAutomaton m f a a -> FilterAutomaton m f a [a]
forall (m :: Type -> Type) a (f :: Type -> Type) a.
(Alternative m, Applicative f) =>
FilterAutomaton m f a a
-> FilterAutomaton m f a a -> FilterAutomaton m f a a
$cempty :: forall (m :: Type -> Type) a (f :: Type -> Type) a.
(Alternative m, Applicative f) =>
FilterAutomaton m f a a
empty :: forall a. FilterAutomaton m f a a
$c<|> :: forall (m :: Type -> Type) a (f :: Type -> Type) a.
(Alternative m, Applicative f) =>
FilterAutomaton m f a a
-> FilterAutomaton m f a a -> FilterAutomaton m f a a
<|> :: forall a.
FilterAutomaton m f a a
-> FilterAutomaton m f a a -> FilterAutomaton m f a a
$csome :: forall (m :: Type -> Type) a (f :: Type -> Type) a.
(Alternative m, Applicative f) =>
FilterAutomaton m f a a -> FilterAutomaton m f a [a]
some :: forall a. FilterAutomaton m f a a -> FilterAutomaton m f a [a]
$cmany :: forall (m :: Type -> Type) a (f :: Type -> Type) a.
(Alternative m, Applicative f) =>
FilterAutomaton m f a a -> FilterAutomaton m f a [a]
many :: forall a. FilterAutomaton m f a a -> FilterAutomaton m f a [a]
Alternative) via Compose (Automaton m a) f

-- | Create a 'FilterAutomaton' that ignores its input from a 'FilterStream'.
fromFilterStream :: (Monad m) => FilterStream m f a -> FilterAutomaton m f any a
fromFilterStream :: forall (m :: Type -> Type) (f :: Type -> Type) a any.
Monad m =>
FilterStream m f a -> FilterAutomaton m f any a
fromFilterStream = Automaton m any (f a) -> FilterAutomaton m f any a
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m any (f a) -> FilterAutomaton m f any a)
-> (FilterStream m f a -> Automaton m any (f a))
-> FilterStream m f a
-> FilterAutomaton m f any a
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. StreamT m (f a) -> Automaton m any (f a)
forall (m :: Type -> Type) a any.
Monad m =>
StreamT m a -> Automaton m any a
fromStream (StreamT m (f a) -> Automaton m any (f a))
-> (FilterStream m f a -> StreamT m (f a))
-> FilterStream m f a
-> Automaton m any (f a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. FilterStream m f a -> StreamT m (f a)
forall (m :: Type -> Type) (f :: Type -> Type) a.
FilterStream m f a -> StreamT m (f a)
getFilterStream

{- | Create a 'FilterStream' from a 'FilterAutomaton'.

The current input can be read as an effect in 'ReaderT'.
-}
toFilterStream :: (Functor m) => FilterAutomaton m f a b -> FilterStream (ReaderT a m) f b
toFilterStream :: forall (m :: Type -> Type) (f :: Type -> Type) a b.
Functor m =>
FilterAutomaton m f a b -> FilterStream (ReaderT a m) f b
toFilterStream = StreamT (ReaderT a m) (f b) -> FilterStream (ReaderT a m) f b
forall (m :: Type -> Type) (f :: Type -> Type) a.
StreamT m (f a) -> FilterStream m f a
FilterStream (StreamT (ReaderT a m) (f b) -> FilterStream (ReaderT a m) f b)
-> (FilterAutomaton m f a b -> StreamT (ReaderT a m) (f b))
-> FilterAutomaton m f a b
-> FilterStream (ReaderT a m) f b
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Automaton m a (f b) -> StreamT (ReaderT a m) (f b)
forall (m :: Type -> Type) a b.
Functor m =>
Automaton m a b -> StreamT (ReaderT a m) b
toStreamT (Automaton m a (f b) -> StreamT (ReaderT a m) (f b))
-> (FilterAutomaton m f a b -> Automaton m a (f b))
-> FilterAutomaton m f a b
-> StreamT (ReaderT a m) (f b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. FilterAutomaton m f a b -> Automaton m a (f b)
forall (m :: Type -> Type) (f :: Type -> Type) a b.
FilterAutomaton m f a b -> Automaton m a (f b)
getFilterAutomaton

-- | Use a filtering function to create a 'FilterAutomaton'.
arrFilter :: (Monad m) => (a -> f b) -> FilterAutomaton m f a b
arrFilter :: forall (m :: Type -> Type) a (f :: Type -> Type) b.
Monad m =>
(a -> f b) -> FilterAutomaton m f a b
arrFilter = Automaton m a (f b) -> FilterAutomaton m f a b
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m a (f b) -> FilterAutomaton m f a b)
-> ((a -> f b) -> Automaton m a (f b))
-> (a -> f b)
-> FilterAutomaton m f a b
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (a -> f b) -> Automaton m a (f b)
forall b c. (b -> c) -> Automaton m b c
forall (a :: Type -> Type -> Type) b c.
Arrow a =>
(b -> c) -> a b c
arr

-- | Filter the input according to a predicate.
filterS :: (Monad m, Filterable f, Applicative f) => (a -> Bool) -> FilterAutomaton m f a a
filterS :: forall (m :: Type -> Type) (f :: Type -> Type) a.
(Monad m, Filterable f, Applicative f) =>
(a -> Bool) -> FilterAutomaton m f a a
filterS a -> Bool
f = (a -> Bool) -> FilterAutomaton m f a a -> FilterAutomaton m f a a
forall a.
(a -> Bool) -> FilterAutomaton m f a a -> FilterAutomaton m f a a
forall (f :: Type -> Type) a.
Filterable f =>
(a -> Bool) -> f a -> f a
filter a -> Bool
f FilterAutomaton m f a a
forall (m :: Type -> Type) (f :: Type -> Type) a.
(Monad m, Applicative f) =>
FilterAutomaton m f a a
id'

{- | Given an @f@-effect in the step, push it into the output type.

This works by internally tracking the @f@ effects in the state, and at the same time joining them in the output.

For example, if @f@ is lists, and @automaton :: Automaton (Compose m []) a b@ creates a 2-element list at some point,
the internal state of @automatonFilter automaton@ will split into two, and there are two outputs.

Likewise, if @f@ is 'Maybe', and a 'Nothing' occurs at some point, then this automaton is deactivated forever.
-}
automatonFilter :: (Monad f, Traversable f, Monad m) => Automaton (Compose m f) a b -> FilterAutomaton m f a b
automatonFilter :: forall (f :: Type -> Type) (m :: Type -> Type) a b.
(Monad f, Traversable f, Monad m) =>
Automaton (Compose m f) a b -> FilterAutomaton m f a b
automatonFilter = Automaton m a (f b) -> FilterAutomaton m f a b
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m a (f b) -> FilterAutomaton m f a b)
-> (Automaton (Compose m f) a b -> Automaton m a (f b))
-> Automaton (Compose m f) a b
-> FilterAutomaton m f a b
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. OptimizedStreamT (ReaderT a m) (f b) -> Automaton m a (f b)
forall (m :: Type -> Type) a b.
OptimizedStreamT (ReaderT a m) b -> Automaton m a b
Automaton (OptimizedStreamT (ReaderT a m) (f b) -> Automaton m a (f b))
-> (Automaton (Compose m f) a b
    -> OptimizedStreamT (ReaderT a m) (f b))
-> Automaton (Compose m f) a b
-> Automaton m a (f b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. StreamT (ReaderT a m) (f b) -> OptimizedStreamT (ReaderT a m) (f b)
forall (m :: Type -> Type) a. StreamT m a -> OptimizedStreamT m a
Stateful (StreamT (ReaderT a m) (f b)
 -> OptimizedStreamT (ReaderT a m) (f b))
-> (Automaton (Compose m f) a b -> StreamT (ReaderT a m) (f b))
-> Automaton (Compose m f) a b
-> OptimizedStreamT (ReaderT a m) (f b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. FilterStream (ReaderT a m) f b -> StreamT (ReaderT a m) (f b)
forall (m :: Type -> Type) (f :: Type -> Type) a.
FilterStream m f a -> StreamT m (f a)
getFilterStream (FilterStream (ReaderT a m) f b -> StreamT (ReaderT a m) (f b))
-> (Automaton (Compose m f) a b -> FilterStream (ReaderT a m) f b)
-> Automaton (Compose m f) a b
-> StreamT (ReaderT a m) (f b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. StreamT (Compose (ReaderT a m) f) b
-> FilterStream (ReaderT a m) f b
forall (f :: Type -> Type) (m :: Type -> Type) a.
(Monad f, Traversable f, Monad m) =>
StreamT (Compose m f) a -> FilterStream m f a
streamFilter (StreamT (Compose (ReaderT a m) f) b
 -> FilterStream (ReaderT a m) f b)
-> (Automaton (Compose m f) a b
    -> StreamT (Compose (ReaderT a m) f) b)
-> Automaton (Compose m f) a b
-> FilterStream (ReaderT a m) f b
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (forall x. ReaderT a (Compose m f) x -> Compose (ReaderT a m) f x)
-> StreamT (ReaderT a (Compose m f)) b
-> StreamT (Compose (ReaderT a m) f) b
forall (m1 :: Type -> Type) (m2 :: Type -> Type) a.
(forall x. m1 x -> m2 x) -> StreamT m1 a -> StreamT m2 a
hoist' (\ReaderT a (Compose m f) x
ramf -> ReaderT a m (f x) -> Compose (ReaderT a m) f x
forall {k} {k1} (f :: k -> Type) (g :: k1 -> k) (a :: k1).
f (g a) -> Compose f g a
Compose (ReaderT a m (f x) -> Compose (ReaderT a m) f x)
-> ReaderT a m (f x) -> Compose (ReaderT a m) f x
forall a b. (a -> b) -> a -> b
$ (a -> m (f x)) -> ReaderT a m (f x)
forall r (m :: Type -> Type) a. (r -> m a) -> ReaderT r m a
ReaderT ((a -> m (f x)) -> ReaderT a m (f x))
-> (a -> m (f x)) -> ReaderT a m (f x)
forall a b. (a -> b) -> a -> b
$ Compose m f x -> m (f x)
forall {k1} {k2} (f :: k1 -> Type) (g :: k2 -> k1) (a :: k2).
Compose f g a -> f (g a)
getCompose (Compose m f x -> m (f x)) -> (a -> Compose m f x) -> a -> m (f x)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ReaderT a (Compose m f) x -> a -> Compose m f x
forall r (m :: Type -> Type) a. ReaderT r m a -> r -> m a
runReaderT ReaderT a (Compose m f) x
ramf) (StreamT (ReaderT a (Compose m f)) b
 -> StreamT (Compose (ReaderT a m) f) b)
-> (Automaton (Compose m f) a b
    -> StreamT (ReaderT a (Compose m f)) b)
-> Automaton (Compose m f) a b
-> StreamT (Compose (ReaderT a m) f) b
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Automaton (Compose m f) a b -> StreamT (ReaderT a (Compose m f)) b
forall (m :: Type -> Type) a b.
Functor m =>
Automaton m a b -> StreamT (ReaderT a m) b
toStreamT

-- | Like 'Category.id', but only requiring @'Applicative' f@.
id' :: (Monad m, Applicative f) => FilterAutomaton m f a a
id' :: forall (m :: Type -> Type) (f :: Type -> Type) a.
(Monad m, Applicative f) =>
FilterAutomaton m f a a
id' = (a -> f a) -> FilterAutomaton m f a a
forall (m :: Type -> Type) a (f :: Type -> Type) b.
Monad m =>
(a -> f b) -> FilterAutomaton m f a b
arrFilter a -> f a
forall a. a -> f a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure

instance (Monad m, Traversable f, Monad f) => Category (FilterAutomaton m f) where
  id :: forall a. FilterAutomaton m f a a
id = FilterAutomaton m f a a
forall (m :: Type -> Type) (f :: Type -> Type) a.
(Monad m, Applicative f) =>
FilterAutomaton m f a a
id'
  FilterAutomaton Automaton m b (f c)
g . :: forall b c a.
FilterAutomaton m f b c
-> FilterAutomaton m f a b -> FilterAutomaton m f a c
. FilterAutomaton Automaton m a (f b)
f = Automaton m a (f c) -> FilterAutomaton m f a c
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m a (f c) -> FilterAutomaton m f a c)
-> Automaton m a (f c) -> FilterAutomaton m f a c
forall a b. (a -> b) -> a -> b
$ Automaton m b (f c) -> Automaton m (f b) (f (f c))
forall (f :: Type -> Type) a b.
Traversable f =>
Automaton m a b -> Automaton m (f a) (f b)
forall (p :: Type -> Type -> Type) (f :: Type -> Type) a b.
(Traversing p, Traversable f) =>
p a b -> p (f a) (f b)
traverse' Automaton m b (f c)
g Automaton m (f b) (f (f c))
-> Automaton m a (f b) -> Automaton m a (f (f c))
forall b c a. Automaton m b c -> Automaton m a b -> Automaton m a c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Automaton m a (f b)
f Automaton m a (f (f c)) -> (f (f c) -> f c) -> Automaton m a (f c)
forall (f :: Type -> Type) a b. Functor f => f a -> (a -> b) -> f b
<&> f (f c) -> f c
forall (m :: Type -> Type) a. Monad m => m (m a) -> m a
join

instance (Monad m, Traversable f, Monad f) => Arrow (FilterAutomaton m f) where
  arr :: forall b c. (b -> c) -> FilterAutomaton m f b c
arr b -> c
f = Automaton m b (f c) -> FilterAutomaton m f b c
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m b (f c) -> FilterAutomaton m f b c)
-> Automaton m b (f c) -> FilterAutomaton m f b c
forall a b. (a -> b) -> a -> b
$ (b -> f c) -> Automaton m b (f c)
forall b c. (b -> c) -> Automaton m b c
forall (a :: Type -> Type -> Type) b c.
Arrow a =>
(b -> c) -> a b c
arr ((b -> f c) -> Automaton m b (f c))
-> (b -> f c) -> Automaton m b (f c)
forall a b. (a -> b) -> a -> b
$ b -> c
f (b -> c) -> (c -> f c) -> b -> f c
forall {k} (cat :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> c -> f c
forall a. a -> f a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure
  first :: forall b c d.
FilterAutomaton m f b c -> FilterAutomaton m f (b, d) (c, d)
first (FilterAutomaton Automaton m b (f c)
automaton) = Automaton m (b, d) (f (c, d)) -> FilterAutomaton m f (b, d) (c, d)
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m (b, d) (f (c, d))
 -> FilterAutomaton m f (b, d) (c, d))
-> Automaton m (b, d) (f (c, d))
-> FilterAutomaton m f (b, d) (c, d)
forall a b. (a -> b) -> a -> b
$ Automaton m b (f c) -> Automaton m (b, d) (f c, d)
forall b c d. Automaton m b c -> Automaton m (b, d) (c, d)
forall (a :: Type -> Type -> Type) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first Automaton m b (f c)
automaton Automaton m (b, d) (f c, d)
-> ((f c, d) -> f (c, d)) -> Automaton m (b, d) (f (c, d))
forall (f :: Type -> Type) a b. Functor f => f a -> (a -> b) -> f b
<&> (\(f c
fc, d
d) -> (,d
d) (c -> (c, d)) -> f c -> f (c, d)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> f c
fc)

instance (Traversable f, Monad m, Monad f) => ArrowChoice (FilterAutomaton m f) where
  FilterAutomaton Automaton m b (f c)
automaton1 +++ :: forall b c b' c'.
FilterAutomaton m f b c
-> FilterAutomaton m f b' c'
-> FilterAutomaton m f (Either b b') (Either c c')
+++ FilterAutomaton Automaton m b' (f c')
automaton2 = Automaton m (Either b b') (f (Either c c'))
-> FilterAutomaton m f (Either b b') (Either c c')
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m (Either b b') (f (Either c c'))
 -> FilterAutomaton m f (Either b b') (Either c c'))
-> Automaton m (Either b b') (f (Either c c'))
-> FilterAutomaton m f (Either b b') (Either c c')
forall a b. (a -> b) -> a -> b
$ Automaton m b (f c)
automaton1 Automaton m b (f c)
-> Automaton m b' (f c')
-> Automaton m (Either b b') (Either (f c) (f c'))
forall b c b' c'.
Automaton m b c
-> Automaton m b' c' -> Automaton m (Either b b') (Either c c')
forall (a :: Type -> Type -> Type) b c b' c'.
ArrowChoice a =>
a b c -> a b' c' -> a (Either b b') (Either c c')
+++ Automaton m b' (f c')
automaton2 Automaton m (Either b b') (Either (f c) (f c'))
-> (Either (f c) (f c') -> f (Either c c'))
-> Automaton m (Either b b') (f (Either c c'))
forall (f :: Type -> Type) a b. Functor f => f a -> (a -> b) -> f b
<&> (f c -> f (Either c c'))
-> (f c' -> f (Either c c'))
-> Either (f c) (f c')
-> f (Either c c')
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either ((c -> Either c c') -> f c -> f (Either c c')
forall a b. (a -> b) -> f a -> f b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap c -> Either c c'
forall a b. a -> Either a b
Left) ((c' -> Either c c') -> f c' -> f (Either c c')
forall a b. (a -> b) -> f a -> f b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap c' -> Either c c'
forall a b. b -> Either a b
Right)

-- | There is no 'Witherable' instance though since it isn't 'Traversable'.
instance (Functor m, Filterable f) => Filterable (FilterAutomaton m f a) where
  mapMaybe :: forall a b.
(a -> Maybe b)
-> FilterAutomaton m f a a -> FilterAutomaton m f a b
mapMaybe a -> Maybe b
f (FilterAutomaton Automaton m a (f a)
automaton) = Automaton m a (f b) -> FilterAutomaton m f a b
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m a (f b) -> FilterAutomaton m f a b)
-> Automaton m a (f b) -> FilterAutomaton m f a b
forall a b. (a -> b) -> a -> b
$ Automaton m a (f a)
automaton Automaton m a (f a) -> (f a -> f b) -> Automaton m a (f b)
forall (f :: Type -> Type) a b. Functor f => f a -> (a -> b) -> f b
<&> (a -> Maybe b) -> f a -> f b
forall a b. (a -> Maybe b) -> f a -> f b
forall (f :: Type -> Type) a b.
Filterable f =>
(a -> Maybe b) -> f a -> f b
mapMaybe a -> Maybe b
f

-- | Lift a regular 'Automaton' (which doesn't filter) to a 'FilterAutomaton'.
liftFilter :: (Monad m, Applicative f) => Automaton m a b -> FilterAutomaton m f a b
liftFilter :: forall (m :: Type -> Type) (f :: Type -> Type) a b.
(Monad m, Applicative f) =>
Automaton m a b -> FilterAutomaton m f a b
liftFilter = Automaton m a (f b) -> FilterAutomaton m f a b
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m a (f b) -> FilterAutomaton m f a b)
-> (Automaton m a b -> Automaton m a (f b))
-> Automaton m a b
-> FilterAutomaton m f a b
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (b -> f b) -> Automaton m a b -> Automaton m a (f b)
forall a b. (a -> b) -> Automaton m a a -> Automaton m a b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap b -> f b
forall a. a -> f a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure

{- | Postcompose with an 'Automaton'.

The postcomposed automaton will be stepped for every output of the filter automaton.
-}
rmapS :: (Traversable f, Monad m) => FilterAutomaton m f a b -> Automaton m b c -> FilterAutomaton m f a c
rmapS :: forall (f :: Type -> Type) (m :: Type -> Type) a b c.
(Traversable f, Monad m) =>
FilterAutomaton m f a b
-> Automaton m b c -> FilterAutomaton m f a c
rmapS (FilterAutomaton Automaton m a (f b)
fa) Automaton m b c
a = Automaton m a (f c) -> FilterAutomaton m f a c
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m a (f c) -> FilterAutomaton m f a c)
-> Automaton m a (f c) -> FilterAutomaton m f a c
forall a b. (a -> b) -> a -> b
$ Automaton m a (f b)
fa Automaton m a (f b)
-> Automaton m (f b) (f c) -> Automaton m a (f c)
forall {k} (cat :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Automaton m b c -> Automaton m (f b) (f c)
forall (f :: Type -> Type) a b.
Traversable f =>
Automaton m a b -> Automaton m (f a) (f b)
forall (p :: Type -> Type -> Type) (f :: Type -> Type) a b.
(Traversing p, Traversable f) =>
p a b -> p (f a) (f b)
traverse' Automaton m b c
a

-- | Precompose with an 'Automaton'.
lmapS :: (Monad m) => Automaton m a b -> FilterAutomaton m f b c -> FilterAutomaton m f a c
lmapS :: forall (m :: Type -> Type) a b (f :: Type -> Type) c.
Monad m =>
Automaton m a b
-> FilterAutomaton m f b c -> FilterAutomaton m f a c
lmapS Automaton m a b
a (FilterAutomaton Automaton m b (f c)
fa) = Automaton m a (f c) -> FilterAutomaton m f a c
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m a (f c) -> FilterAutomaton m f a c)
-> Automaton m a (f c) -> FilterAutomaton m f a c
forall a b. (a -> b) -> a -> b
$ Automaton m a b
a Automaton m a b -> Automaton m b (f c) -> Automaton m a (f c)
forall {k} (cat :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> Automaton m b (f c)
fa

instance (Functor m, Functor f) => Profunctor (FilterAutomaton m f) where
  dimap :: forall a b c d.
(a -> b)
-> (c -> d) -> FilterAutomaton m f b c -> FilterAutomaton m f a d
dimap a -> b
f c -> d
g FilterAutomaton {Automaton m b (f c)
getFilterAutomaton :: forall (m :: Type -> Type) (f :: Type -> Type) a b.
FilterAutomaton m f a b -> Automaton m a (f b)
getFilterAutomaton :: Automaton m b (f c)
getFilterAutomaton} = Automaton m a (f d) -> FilterAutomaton m f a d
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m a (f d) -> FilterAutomaton m f a d)
-> Automaton m a (f d) -> FilterAutomaton m f a d
forall a b. (a -> b) -> a -> b
$ (a -> b)
-> (f c -> f d) -> Automaton m b (f c) -> Automaton m a (f d)
forall a b c d.
(a -> b) -> (c -> d) -> Automaton m b c -> Automaton m a d
forall (p :: Type -> Type -> Type) a b c d.
Profunctor p =>
(a -> b) -> (c -> d) -> p b c -> p a d
dimap a -> b
f ((c -> d) -> f c -> f d
forall a b. (a -> b) -> f a -> f b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap c -> d
g) Automaton m b (f c)
getFilterAutomaton

instance (Monad m, Monad f, Traversable f) => Strong (FilterAutomaton m f) where
  first' :: forall a b c.
FilterAutomaton m f a b -> FilterAutomaton m f (a, c) (b, c)
first' = FilterAutomaton m f a b -> FilterAutomaton m f (a, c) (b, c)
forall a b c.
FilterAutomaton m f a b -> FilterAutomaton m f (a, c) (b, c)
forall (a :: Type -> Type -> Type) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first

instance (Monad m, Monad f, Traversable f) => Choice (FilterAutomaton m f) where
  left' :: forall a b c.
FilterAutomaton m f a b
-> FilterAutomaton m f (Either a c) (Either b c)
left' = FilterAutomaton m f a b
-> FilterAutomaton m f (Either a c) (Either b c)
forall a b c.
FilterAutomaton m f a b
-> FilterAutomaton m f (Either a c) (Either b c)
forall (a :: Type -> Type -> Type) b c d.
ArrowChoice a =>
a b c -> a (Either b d) (Either c d)
left

-- | When looping, this will break when any of the positions in @f@ breaks.
instance (Monad m, Traversable f) => Cochoice (FilterAutomaton m f) where
  unright :: forall d a b.
FilterAutomaton m f (Either d a) (Either d b)
-> FilterAutomaton m f a b
unright = Automaton m a (f b) -> FilterAutomaton m f a b
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m a (f b) -> FilterAutomaton m f a b)
-> (FilterAutomaton m f (Either d a) (Either d b)
    -> Automaton m a (f b))
-> FilterAutomaton m f (Either d a) (Either d b)
-> FilterAutomaton m f a b
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Automaton m (Either d a) (Either d (f b)) -> Automaton m a (f b)
forall d a b.
Automaton m (Either d a) (Either d b) -> Automaton m a b
forall (p :: Type -> Type -> Type) d a b.
Cochoice p =>
p (Either d a) (Either d b) -> p a b
unright (Automaton m (Either d a) (Either d (f b)) -> Automaton m a (f b))
-> (FilterAutomaton m f (Either d a) (Either d b)
    -> Automaton m (Either d a) (Either d (f b)))
-> FilterAutomaton m f (Either d a) (Either d b)
-> Automaton m a (f b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (f (Either d b) -> Either d (f b))
-> Automaton m (Either d a) (f (Either d b))
-> Automaton m (Either d a) (Either d (f b))
forall a b.
(a -> b)
-> Automaton m (Either d a) a -> Automaton m (Either d a) b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap f (Either d b) -> Either d (f b)
forall (t :: Type -> Type) (m :: Type -> Type) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
forall (m :: Type -> Type) a. Monad m => f (m a) -> m (f a)
sequence (Automaton m (Either d a) (f (Either d b))
 -> Automaton m (Either d a) (Either d (f b)))
-> (FilterAutomaton m f (Either d a) (Either d b)
    -> Automaton m (Either d a) (f (Either d b)))
-> FilterAutomaton m f (Either d a) (Either d b)
-> Automaton m (Either d a) (Either d (f b))
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. FilterAutomaton m f (Either d a) (Either d b)
-> Automaton m (Either d a) (f (Either d b))
forall (m :: Type -> Type) (f :: Type -> Type) a b.
FilterAutomaton m f a b -> Automaton m a (f b)
getFilterAutomaton

-- | Run two automata in parallel and 'align' their outputs.
instance (Applicative m, Semialign f) => Semialign (FilterAutomaton m f a) where
  align :: forall a b.
FilterAutomaton m f a a
-> FilterAutomaton m f a b -> FilterAutomaton m f a (These a b)
align FilterAutomaton m f a a
fa1 FilterAutomaton m f a b
fa2 = Automaton m a (f (These a b)) -> FilterAutomaton m f a (These a b)
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m a (f (These a b))
 -> FilterAutomaton m f a (These a b))
-> Automaton m a (f (These a b))
-> FilterAutomaton m f a (These a b)
forall a b. (a -> b) -> a -> b
$ f a -> f b -> f (These a b)
forall a b. f a -> f b -> f (These a b)
forall (f :: Type -> Type) a b.
Semialign f =>
f a -> f b -> f (These a b)
align (f a -> f b -> f (These a b))
-> Automaton m a (f a) -> Automaton m a (f b -> f (These a b))
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> FilterAutomaton m f a a -> Automaton m a (f a)
forall (m :: Type -> Type) (f :: Type -> Type) a b.
FilterAutomaton m f a b -> Automaton m a (f b)
getFilterAutomaton FilterAutomaton m f a a
fa1 Automaton m a (f b -> f (These a b))
-> Automaton m a (f b) -> Automaton m a (f (These a b))
forall a b.
Automaton m a (a -> b) -> Automaton m a a -> Automaton m a b
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> FilterAutomaton m f a b -> Automaton m a (f b)
forall (m :: Type -> Type) (f :: Type -> Type) a b.
FilterAutomaton m f a b -> Automaton m a (f b)
getFilterAutomaton FilterAutomaton m f a b
fa2

-- | Constantly output the empty shape.
instance (Applicative m, Align f) => Align (FilterAutomaton m f a) where
  nil :: forall a. FilterAutomaton m f a a
nil = Automaton m a (f a) -> FilterAutomaton m f a a
forall (m :: Type -> Type) (f :: Type -> Type) a b.
Automaton m a (f b) -> FilterAutomaton m f a b
FilterAutomaton (Automaton m a (f a) -> FilterAutomaton m f a a)
-> Automaton m a (f a) -> FilterAutomaton m f a a
forall a b. (a -> b) -> a -> b
$ m (f a) -> Automaton m a (f a)
forall (m :: Type -> Type) b a. Functor m => m b -> Automaton m a b
constM (m (f a) -> Automaton m a (f a)) -> m (f a) -> Automaton m a (f a)
forall a b. (a -> b) -> a -> b
$ f a -> m (f a)
forall a. a -> m a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure f a
forall a. f a
forall (f :: Type -> Type) a. Align f => f a
nil