module Haskus.Utils.Flow
   ( Flow
   , IOV
   , MonadIO (..)
   , MonadInIO (..)
   
   , flowRes
   , flowSingle
   , flowSetN
   , flowSet
   , flowLift
   , flowToCont
   , flowTraverse
   , flowFor
   , flowTraverseFilter
   , flowForFilter
   , Liftable
   , Popable
   , MaybePopable
   
   , (|>)
   , (<|)
   , (||>)
   , (<||)
   
   , when
   , unless
   , whenM
   , unlessM
   , ifM
   , guard
   , void
   , forever
   , foldM
   , foldM_
   , forM
   , forM_
   , mapM
   , mapM_
   , sequence
   , replicateM
   , replicateM_
   , filterM
   , join
   , (<=<)
   , (>=>)
   , loopM
   , whileM
   
   , flowMap
   , flowBind
   , flowBind'
   , flowMatch
   , flowMatchFail
   
   , (.~.>)
   , (>.~.>)
   , (.~+>)
   , (>.~+>)
   , (.~^^>)
   , (>.~^^>)
   , (.~^>)
   , (>.~^>)
   , (.~$>)
   , (>.~$>)
   , (.~|>)
   , (>.~|>)
   , (.~=>)
   , (>.~=>)
   , (.~!>)
   , (>.~!>)
   , (.~!!>)
   , (>.~!!>)
   
   , (.-.>)
   , (>.-.>)
   , (<.-.)
   , (<.-.<)
   
   , (<$<)
   , (<*<)
   , (<|<)
   
   , (.~~.>)
   , (>.~~.>)
   , (.~~+>)
   , (>.~~+>)
   , (.~~^^>)
   , (>.~~^^>)
   , (.~~^>)
   , (>.~~^>)
   , (.~~$>)
   , (>.~~$>)
   , (.~~|>)
   , (>.~~|>)
   , (.~~=>)
   , (>.~~=>)
   , (.~~!>)
   , (>.~~!>)
   
   , (..~.>)
   , (>..~.>)
   , (..-.>)
   , (>..-.>)
   , (..-..>)
   , (>..-..>)
   , (..~..>)
   , (>..~..>)
   , (..~^^>)
   , (>..~^^>)
   , (..~^>)
   , (>..~^>)
   , (..~=>)
   , (>..~=>)
   , (..~!>)
   , (>..~!>)
   , (..~!!>)
   , (>..~!!>)
   
   , (..%~^>)
   , (>..%~^>)
   , (..%~^^>)
   , (>..%~^^>)
   , (..%~$>)
   , (>..%~$>)
   , (..%~!!>)
   , (>..%~!!>)
   , (..%~!>)
   , (>..%~!>)
   , (..?~^>)
   , (>..?~^>)
   , (..?~^^>)
   , (>..?~^^>)
   , (..?~$>)
   , (>..?~$>)
   , (..?~!!>)
   , (>..?~!!>)
   , (..?~!>)
   , (>..?~!>)
   
   , (%~.>)
   , (>%~.>)
   , (%~+>)
   , (>%~+>)
   , (%~^^>)
   , (>%~^^>)
   , (%~^>)
   , (>%~^>)
   , (%~$>)
   , (>%~$>)
   , (%~|>)
   , (>%~|>)
   , (%~=>)
   , (>%~=>)
   , (%~!>)
   , (>%~!>)
   , (%~!!>)
   , (>%~!!>)
   , (?~.>)
   , (>?~.>)
   , (?~+>)
   , (>?~+>)
   , (?~^^>)
   , (>?~^^>)
   , (?~^>)
   , (>?~^>)
   , (?~$>)
   , (>?~$>)
   , (?~|>)
   , (>?~|>)
   , (?~=>)
   , (>?~=>)
   , (?~!>)
   , (>?~!>)
   , (?~!!>)
   , (>?~!!>)
   
   , makeFlowOp
   , makeFlowOpM
   , selectTail
   , selectFirst
   , selectType
   , applyConst
   , applyPure
   , applyM
   , applyF
   , combineFirst
   , combineSameTail
   , combineEither
   , combineConcat
   , combineUnion
   , combineLiftUnselected
   , combineLiftBoth
   , combineSingle
   , liftV
   , liftF
   )
where
import Haskus.Utils.Variant
import Haskus.Utils.Types
import Haskus.Utils.Types.List
import Haskus.Utils.Monad
import Haskus.Utils.ContFlow
type Flow m (l :: [*]) = m (Variant l)
type IOV l = Flow IO l
flowSetN :: forall (n :: Nat) xs m.
   ( Monad m
   , KnownNat n
   ) => Index n xs -> Flow m xs
flowSetN = return . toVariantAt @n
flowSet :: (Member x xs, Monad m) => x -> Flow m xs
flowSet = return . toVariant
flowSingle :: Monad m => x -> Flow m '[x]
flowSingle = flowSetN @0
flowLift :: (Liftable xs ys , Monad m) => Flow m xs -> Flow m ys
flowLift = fmap liftVariant
flowToCont :: (ContVariant xs, Monad m) => Flow m xs -> ContFlow xs (m r)
flowToCont = variantToContM
flowTraverse :: forall m a b xs.
   ( Monad m
   ) => (a -> Flow m (b ': xs)) -> [a] -> Flow m ([b] ': xs)
flowTraverse f = go (flowSetN @0 [])
   where
      go :: Flow m ([b] ': xs) -> [a] -> Flow m ([b] ': xs)
      go rs []     = rs >.-.> reverse
      go rs (a:as) = go rs' as
         where
            
            
            rs' = rs >.~$> \bs -> (f a >.-.> (:bs))
flowFor :: forall m a b xs.
   ( Monad m
   ) => [a] -> (a -> Flow m (b ': xs)) -> Flow m ([b] ': xs)
flowFor = flip flowTraverse
flowTraverseFilter :: forall m a b xs.
   ( Monad m
   ) => (a -> Flow m (b ': xs)) -> [a] -> m [b]
flowTraverseFilter f = go
   where
      go :: [a] -> m [b]
      go []     = return []
      go (a:as) = do
         f a >.~.> (\b -> (b:) <$> go as)
             >..~.> const (go as)
flowForFilter :: forall m a b xs.
   ( Monad m
   ) => [a] -> (a -> Flow m (b ': xs)) -> m [b]
flowForFilter = flip flowTraverseFilter
flowRes :: Functor m => Flow m '[x] -> m x
flowRes = fmap variantToValue
liftm :: Monad m => (Variant x -> a -> m b) -> Flow m x -> a -> m b
liftm op x a = do
   x' <- x
   op x' a
(|>) :: a -> (a -> b) -> b
x |> f = f x
infixl 0 |>
(<|) :: (a -> b) -> a -> b
f <| x = f x
infixr 0 <|
(||>) :: Functor f => f a -> (a -> b) -> f b
x ||> f = fmap f x
infixl 0 ||>
(<||) :: Functor f => (a -> b) -> f a -> f b
f <|| x = fmap f x
infixr 0 <||
flowMap :: Monad m => Flow m (x ': xs) -> (x -> y) -> Flow m (y ': xs)
flowMap = (>.-.>)
flowBind :: forall xs ys zs m x.
   ( Liftable xs zs
   , Liftable ys zs
   , zs ~ Union xs ys
   , Monad m
   ) => Flow m (x ': ys) -> (x -> Flow m xs) -> Flow m zs
flowBind = (>.~|>)
flowBind' :: Monad m => Flow m (x ': xs) -> (x -> Flow m (y ': xs)) -> Flow m (y ': xs)
flowBind' = (>.~$>)
flowMatch :: forall x xs zs m.
   ( Monad m
   , Popable x xs
   , Liftable (Filter x xs) zs
   ) => Flow m xs -> (x -> Flow m zs) -> Flow m zs
flowMatch = (>%~^>)
flowMatchFail :: forall x xs m.
   ( Monad m
   , Popable x xs
   ) => Flow m xs -> (x -> m ()) -> Flow m (Filter x xs)
flowMatchFail = (>%~!!>)
(.~.>) :: forall m l x a.
   ( Monad m )
   => Variant (a ': l) -> (a -> m x) -> Flow m (x ': l)
(.~.>) v f = makeFlowOp selectFirst (applyM f) combineFirst v
infixl 0 .~.>
(>.~.>) :: forall m l x a.
   ( Monad m )
   => Flow m (a ': l) -> (a -> m x) -> Flow m (x ': l)
(>.~.>) = liftm (.~.>)
infixl 0 >.~.>
(.~+>) :: forall (k :: Nat) m l l2 a.
   ( KnownNat k
   , k ~ Length l2
   , Monad m )
   => Variant (a ': l) -> (a -> Flow m l2) -> Flow m (Concat l2 l)
(.~+>) v f = makeFlowOp selectFirst (applyF f) combineConcat v
infixl 0 .~+>
(>.~+>) :: forall (k :: Nat) m l l2 a.
   ( KnownNat k
   , k ~ Length l2
   , Monad m )
   => Flow m (a ': l) -> (a -> Flow m l2) -> Flow m (Concat l2 l)
(>.~+>) = liftm (.~+>)
infixl 0 >.~+>
(.~^^>) :: forall m a xs ys zs.
   ( Monad m
   , Liftable xs zs
   , Liftable ys zs
   ) => Variant (a ': ys) -> (a -> Flow m xs) -> Flow m zs
(.~^^>) v f = makeFlowOp selectFirst (applyF f) combineLiftBoth v
infixl 0 .~^^>
(>.~^^>) :: forall m a xs ys zs.
   ( Monad m
   , Liftable xs zs
   , Liftable ys zs
   ) => Flow m (a ': ys) -> (a -> Flow m xs) -> Flow m zs
(>.~^^>) = liftm (.~^^>)
infixl 0 >.~^^>
(.~^>) :: forall m a ys zs.
   ( Monad m
   , Liftable ys zs
   ) => Variant (a ': ys) -> (a -> Flow m zs) -> Flow m zs
(.~^>) v f = makeFlowOp selectFirst (applyF f) combineLiftUnselected v
infixl 0 .~^>
(>.~^>) :: forall m a ys zs.
   ( Monad m
   , Liftable ys zs
   ) => Flow m (a ': ys) -> (a -> Flow m zs) -> Flow m zs
(>.~^>) = liftm (.~^>)
infixl 0 >.~^>
(.~$>) :: forall m x xs a.
   ( Monad m
   ) => Variant (a ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)
(.~$>) v f = makeFlowOp selectFirst (applyF f) combineSameTail v
infixl 0 .~$>
(>.~$>) :: forall m x xs a.
   ( Monad m
   ) => Flow m (a ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)
(>.~$>) = liftm (.~$>)
infixl 0 >.~$>
(.~|>) ::
   ( Liftable xs zs
   , Liftable ys zs
   , zs ~ Union xs ys
   , Monad m
   ) => Variant (a ': ys) -> (a -> Flow m xs) -> Flow m zs
(.~|>) v f = makeFlowOp selectFirst (applyF f) combineUnion v
infixl 0 .~|>
(>.~|>) ::
   ( Liftable xs zs
   , Liftable ys zs
   , zs ~ Union xs ys
   , Monad m
   ) => Flow m (a ': ys) -> (a -> Flow m xs) -> Flow m zs
(>.~|>) = liftm (.~|>)
infixl 0 >.~|>
(.~=>) ::
   ( Monad m
   ) => Variant (a ': l) -> (a -> m ()) -> Flow m (a ': l)
(.~=>) v f = case popVariantHead v of
   Right u -> f u >> return v
   Left  _ -> return v
infixl 0 .~=>
(>.~=>) ::
   ( Monad m
   ) => Flow m (a ': l) -> (a -> m ()) -> Flow m (a ': l)
(>.~=>) = liftm (.~=>)
infixl 0 >.~=>
(.~!>) ::
   ( Monad m
   ) => Variant (a ': l) -> (a -> m ()) -> m ()
(.~!>) v f = case popVariantHead v of
   Right u -> f u
   Left  _ -> return ()
infixl 0 .~!>
(>.~!>) ::
   ( Monad m
   ) => Flow m (a ': l) -> (a -> m ()) -> m ()
(>.~!>) = liftm (.~!>)
infixl 0 >.~!>
(.~!!>) ::
   ( Monad m
   ) => Variant (a ': l) -> (a -> m ()) -> m (Variant l)
(.~!!>) v f = case popVariantHead v of
   Right u -> f u >> error ".~!!> error"
   Left  l -> return l
infixl 0 .~!!>
(>.~!!>) ::
   ( Monad m
   ) => Flow m (a ': l) -> (a -> m ()) -> m (Variant l)
(>.~!!>) = liftm (.~!!>)
infixl 0 >.~!!>
(.-.>) :: forall m l x a.
   ( Monad m )
   => Variant (a ': l) -> (a -> x) -> Flow m (x ': l)
(.-.>) v f = makeFlowOp selectFirst (applyPure (liftV f)) combineFirst v
infixl 0 .-.>
(>.-.>) :: forall m l x a.
   ( Monad m )
   => Flow m (a ': l) -> (a -> x) -> Flow m (x ': l)
(>.-.>) = liftm (.-.>)
infixl 0 >.-.>
(<.-.) :: forall m l x a.
   ( Monad m )
   => (a -> x) -> Variant (a ': l) -> Flow m (x ': l)
(<.-.) = flip (.-.>)
infixr 0 <.-.
(<.-.<) :: forall m l x a.
   ( Monad m )
   => (a -> x) -> Flow m (a ': l) -> Flow m (x ': l)
(<.-.<) = flip (>.-.>)
infixr 0 <.-.<
(<$<) :: forall m l a b.
   ( Monad m )
   => (a -> b) -> Flow m (a ': l) -> Flow m (b ': l)
(<$<) = (<.-.<)
infixl 4 <$<
(<*<) :: forall m l a b.
   ( Monad m )
   => Flow m ((a -> b) ': l) -> Flow m (a ': l) -> Flow m (b ': l)
(<*<) mf mg = mf >.~$> (mg >.-.>)
infixl 4 <*<
(<|<) :: forall m xs ys zs y z.
   ( Monad m
   , Liftable xs zs
   , Liftable ys zs
   , zs ~ Union xs ys
   ) => Flow m ((y -> z) ': xs) -> Flow m (y ': ys) -> Flow m (z ': zs)
(<|<) mf mg = 
   mf >..-..> liftVariant
      >.~$> (\f -> mg >..-..> liftVariant
                      >.-.> f
            )
infixl 4 <|<
(.~~.>) :: forall m l x a.
   ( Monad m )
   => Variant (a ': l) -> m x -> Flow m (x ': l)
(.~~.>) v f = v .~.> const f
infixl 0 .~~.>
(>.~~.>) :: forall m l x a.
   ( Monad m )
   => Flow m (a ': l) -> m x -> Flow m (x ': l)
(>.~~.>) = liftm (.~~.>)
infixl 0 >.~~.>
(.~~+>) :: forall (k :: Nat) m l l2 a.
   ( KnownNat k
   , k ~ Length l2
   , Monad m )
   => Variant (a ': l) -> Flow m l2 -> Flow m (Concat l2 l)
(.~~+>) v f = v .~+> const f
infixl 0 .~~+>
(>.~~+>) :: forall (k :: Nat) m l l2 a.
   ( KnownNat k
   , k ~ Length l2
   , Monad m )
   => Flow m (a ': l) -> Flow m l2 -> Flow m (Concat l2 l)
(>.~~+>) = liftm (.~~+>)
infixl 0 >.~~+>
(.~~^^>) :: forall m a xs ys zs.
   ( Monad m
   , Liftable xs zs
   , Liftable ys zs
   ) => Variant (a ': ys) -> Flow m xs -> Flow m zs
(.~~^^>) v f = v .~^^> const f
infixl 0 .~~^^>
(>.~~^^>) :: forall m a xs ys zs.
   ( Monad m
   , Liftable xs zs
   , Liftable ys zs
   ) => Flow m (a ': ys) -> Flow m xs -> Flow m zs
(>.~~^^>) = liftm (.~~^^>)
infixl 0 >.~~^^>
(.~~^>) :: forall m a ys zs.
   ( Monad m
   , Liftable ys zs
   ) => Variant (a ': ys) -> Flow m zs -> Flow m zs
(.~~^>) v f = v .~^> const f
infixl 0 .~~^>
(>.~~^>) :: forall m a ys zs.
   ( Monad m
   , Liftable ys zs
   ) => Flow m (a ': ys) -> Flow m zs -> Flow m zs
(>.~~^>) = liftm (.~~^>)
infixl 0 >.~~^>
(.~~$>) :: forall m x xs a.
   ( Monad m
   ) => Variant (a ': xs) -> Flow m (x ': xs) -> Flow m (x ': xs)
(.~~$>) v f = v .~$> const f
infixl 0 .~~$>
(>.~~$>) :: forall m x xs a.
   ( Monad m
   ) => Flow m (a ': xs) -> Flow m (x ': xs) -> Flow m (x ': xs)
(>.~~$>) = liftm (.~~$>)
infixl 0 >.~~$>
(.~~|>) ::
   ( Liftable xs zs
   , Liftable ys zs
   , zs ~ Union xs ys
   , Monad m
   ) => Variant (a ': ys) -> Flow m xs -> Flow m zs
(.~~|>) v f = v .~|> const f
infixl 0 .~~|>
(>.~~|>) ::
   ( Liftable xs zs
   , Liftable ys zs
   , zs ~ Union xs ys
   , Monad m
   ) => Flow m (a ': ys) -> Flow m xs -> Flow m zs
(>.~~|>) = liftm (.~~|>)
infixl 0 >.~~|>
(.~~=>) ::
   ( Monad m
   ) => Variant (a ': l) -> m () -> Flow m (a ': l)
(.~~=>) v f = v .~=> const f
infixl 0 .~~=>
(>.~~=>) ::
   ( Monad m
   ) => Flow m (a ': l) -> m () -> Flow m (a ': l)
(>.~~=>) = liftm (.~~=>)
infixl 0 >.~~=>
(.~~!>) ::
   ( Monad m
   ) => Variant (a ': l) -> m () -> m ()
(.~~!>) v f = v .~!> const f
infixl 0 .~~!>
(>.~~!>) ::
   ( Monad m
   ) => Flow m (a ': l) -> m () -> m ()
(>.~~!>) = liftm (.~~!>)
infixl 0 >.~~!>
(..~.>) ::
   ( Monad m
   ) => Variant (a ': l) -> (Variant l -> m a) -> m a
(..~.>) v f = makeFlowOp selectTail (applyVM f) combineSingle v
infixl 0 ..~.>
(>..~.>) ::
   ( Monad m
   ) => Flow m (a ': l) -> (Variant l -> m a) -> m a
(>..~.>) = liftm (..~.>)
infixl 0 >..~.>
(..-.>) ::
   ( Monad m
   ) => Variant (a ': l) -> (Variant l -> a) -> m a
(..-.>) v f = case popVariantHead v of
   Right u -> return u
   Left  l -> return (f l)
infixl 0 ..-.>
(>..-.>) ::
   ( Monad m
   ) => Flow m (a ': l) -> (Variant l -> a) -> m a
(>..-.>) = liftm (..-.>)
infixl 0 >..-.>
(..-..>) :: forall a l xs m.
   ( Monad m
   ) => Variant (a ': l) -> (Variant l -> Variant xs) -> Flow m (a ': xs)
(..-..>) v f = case popVariantHead v of
   Right u -> flowSetN @0 u
   Left  l -> return (prependVariant @'[a] (f l))
infixl 0 ..-..>
(>..-..>) ::
   ( Monad m
   ) => Flow m (a ': l) -> (Variant l -> Variant xs) -> Flow m (a ': xs)
(>..-..>) = liftm (..-..>)
infixl 0 >..-..>
(..~..>) :: forall a l xs m.
   ( Monad m
   ) => Variant (a ': l) -> (Variant l -> Flow m xs) -> Flow m (a ': xs)
(..~..>) v f = case popVariantHead v of
   Right u -> flowSetN @0 u
   Left  l -> prependVariant @'[a] <$> f l
infixl 0 ..~..>
(>..~..>) ::
   ( Monad m
   ) => Flow m (a ': l) -> (Variant l -> Flow m xs) -> Flow m (a ': xs)
(>..~..>) = liftm (..~..>)
infixl 0 >..~..>
(..~^^>) ::
   ( Monad m
   , Liftable xs (a ': zs)
   ) => Variant (a ': l) -> (Variant l -> Flow m xs) -> Flow m (a ': zs)
(..~^^>) v f = case popVariantHead v of
   Right u -> flowSetN @0 u
   Left  l -> liftVariant <$> f l
infixl 0 ..~^^>
(>..~^^>) ::
   ( Monad m
   , Liftable xs (a ': zs)
   ) => Flow m  (a ': l) -> (Variant l -> Flow m xs) -> Flow m (a ': zs)
(>..~^^>) = liftm (..~^^>)
infixl 0 >..~^^>
(..~^>) ::
   ( Monad m
   , Member a zs
   ) => Variant (a ': l) -> (Variant l -> Flow m zs) -> Flow m zs
(..~^>) v f = case popVariantHead v of
   Right u -> flowSet u
   Left  l -> f l
infixl 0 ..~^>
(>..~^>) ::
   ( Monad m
   , Member a zs
   ) => Flow m (a ': l) -> (Variant l -> Flow m zs) -> Flow m zs
(>..~^>) = liftm (..~^>)
infixl 0 >..~^>
(..?~^>) ::
   ( Monad m
   , MaybePopable a xs
   , Liftable (Filter a xs) ys
   ) => Variant (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': ys)
(..?~^>) v f = v ..~..> (\v' -> v' ?~^> f)
infixl 0 ..?~^>
(>..?~^>) ::
   ( Monad m
   , MaybePopable a xs
   , Liftable (Filter a xs) ys
   ) => Flow m (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': ys)
(>..?~^>) = liftm (..?~^>)
infixl 0 >..?~^>
(..%~^>) ::
   ( Monad m
   , Popable a xs
   , Liftable (Filter a xs) ys
   ) => Variant (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': ys)
(..%~^>) v f = v ..~..> (\v' -> v' %~^> f)
infixl 0 ..%~^>
(>..%~^>) ::
   ( Monad m
   , Popable a xs
   , Liftable (Filter a xs) ys
   ) => Flow m (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': ys)
(>..%~^>) = liftm (..%~^>)
infixl 0 >..%~^>
(..?~^^>) ::
   ( Monad m
   , MaybePopable a xs
   , Liftable (Filter a xs) zs
   , Liftable ys zs
   ) => Variant (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': zs)
(..?~^^>) v f = v ..~..> (\v' -> v' ?~^^> f)
infixl 0 ..?~^^>
(>..?~^^>) ::
   ( Monad m
   , MaybePopable a xs
   , Liftable (Filter a xs) zs
   , Liftable ys zs
   ) => Flow m (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': zs)
(>..?~^^>) = liftm (..?~^^>)
infixl 0 >..?~^^>
(..%~^^>) ::
   ( Monad m
   , Popable a xs
   , Liftable (Filter a xs) zs
   , Liftable ys zs
   ) => Variant (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': zs)
(..%~^^>) v f = v ..~..> (\v' -> v' %~^^> f)
infixl 0 ..%~^^>
(>..%~^^>) ::
   ( Monad m
   , Popable a xs
   , Liftable (Filter a xs) zs
   , Liftable ys zs
   ) => Flow m (x ': xs) -> (a -> Flow m ys) -> Flow m (x ': zs)
(>..%~^^>) = liftm (..%~^^>)
infixl 0 >..%~^^>
(..?~$>) ::
   ( Monad m
   , MaybePopable a xs
   , Liftable (Filter a xs) (x ': xs)
   ) => Variant (x ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)
(..?~$>) v f = case popVariantHead v of
   Right _ -> return v
   Left xs -> xs ?~^> f
infixl 0 ..?~$>
(>..?~$>) ::
   ( Monad m
   , MaybePopable a xs
   , Liftable (Filter a xs) (x ': xs)
   ) => Flow m (x ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)
(>..?~$>) = liftm (..?~$>)
infixl 0 >..?~$>
(..%~$>) ::
   ( Monad m
   , Popable a xs
   , Liftable (Filter a xs) (x ': xs)
   ) => Variant (x ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)
(..%~$>) v f = case popVariantHead v of
   Right _ -> return v
   Left xs -> xs %~^> f
infixl 0 ..%~$>
(>..%~$>) ::
   ( Monad m
   , Popable a xs
   , Liftable (Filter a xs) (x ': xs)
   ) => Flow m (x ': xs) -> (a -> Flow m (x ': xs)) -> Flow m (x ': xs)
(>..%~$>) = liftm (..%~$>)
infixl 0 >..%~$>
(..~=>) ::
   ( Monad m
   ) => Variant (x ': xs) -> (Variant xs -> m ()) -> Flow m (x ': xs)
(..~=>) v f = case popVariantHead v of
   Right _ -> return v
   Left  l -> f l >> return v
infixl 0 ..~=>
(>..~=>) ::
   ( Monad m
   ) => Flow m (x ': xs) -> (Variant xs -> m ()) -> Flow m (x ': xs)
(>..~=>) = liftm (..~=>)
infixl 0 >..~=>
(..~!>) ::
   ( Monad m
   ) => Variant (x ': xs) -> (Variant xs -> m ()) -> m ()
(..~!>) v f = case popVariantHead v of
   Right _ -> return ()
   Left  l -> f l
infixl 0 ..~!>
(>..~!>) ::
   ( Monad m
   ) => Flow m (x ': xs) -> (Variant xs -> m ()) -> m ()
(>..~!>) = liftm (..~!>)
infixl 0 >..~!>
(..~!!>) ::
   ( Monad m
   ) => Variant (x ': xs) -> (Variant xs -> m ()) -> m x
(..~!!>) v f = case popVariantHead v of
   Right x -> return x
   Left xs -> f xs >> error "..~!!> error"
infixl 0 ..~!!>
(>..~!!>) ::
   ( Monad m
   ) => Flow m (x ': xs) -> (Variant xs -> m ()) -> m x
(>..~!!>) = liftm (..~!!>)
infixl 0 >..~!!>
(..?~!!>) ::
   ( Monad m
   , MaybePopable y xs
   ) => Variant (x ': xs) -> (y -> m ()) -> Flow m (x ': Filter y xs)
(..?~!!>) v f = v ..~..> (\xs -> xs ?~!!> f)
infixl 0 ..?~!!>
(>..?~!!>) ::
   ( Monad m
   , MaybePopable y xs
   ) => Flow m (x ': xs) -> (y -> m ()) -> Flow m (x ': Filter y xs)
(>..?~!!>) = liftm (..?~!!>)
infixl 0 >..?~!!>
(..%~!!>) ::
   ( Monad m
   , Popable y xs
   ) => Variant (x ': xs) -> (y -> m ()) -> Flow m (x ': Filter y xs)
(..%~!!>) v f = v ..~..> (\xs -> xs %~!!> f)
infixl 0 ..%~!!>
(>..%~!!>) ::
   ( Monad m
   , Popable y xs
   ) => Flow m (x ': xs) -> (y -> m ()) -> Flow m (x ': Filter y xs)
(>..%~!!>) = liftm (..%~!!>)
infixl 0 >..%~!!>
(..?~!>) ::
   ( Monad m
   , MaybePopable y xs
   ) => Variant (x ': xs) -> (y -> m ()) -> m ()
(..?~!>) v f = case popVariantHead v of
   Right _ -> return ()
   Left xs -> xs ?~!> f
infixl 0 ..?~!>
(>..?~!>) ::
   ( Monad m
   , MaybePopable y xs
   ) => Flow m (x ': xs) -> (y -> m ()) -> m ()
(>..?~!>) = liftm (..?~!>)
infixl 0 >..?~!>
(..%~!>) ::
   ( Monad m
   , Popable y xs
   ) => Variant (x ': xs) -> (y -> m ()) -> m ()
(..%~!>) v f = case popVariantHead v of
   Right _ -> return ()
   Left xs -> xs %~!> f
infixl 0 ..%~!>
(>..%~!>) ::
   ( Monad m
   , Popable y xs
   ) => Flow m (x ': xs) -> (y -> m ()) -> m ()
(>..%~!>) = liftm (..%~!>)
infixl 0 >..%~!>
(?~.>) :: forall x xs y ys m.
   ( ys ~ Filter x xs
   , Monad m
   , MaybePopable x xs
   ) => Variant xs -> (x -> m y) -> Flow m (y ': ys)
(?~.>) v f = case popVariantMaybe v of
   Right x -> flowSetN @0 =<< f x
   Left ys -> prependVariant @'[y] <$> return ys
infixl 0 ?~.>
(>?~.>) ::
   ( ys ~ Filter x xs
   , Monad m
   , MaybePopable x xs
   ) => Flow m xs -> (x -> m y) -> Flow m (y ': ys)
(>?~.>) = liftm (?~.>)
infixl 0 >?~.>
(%~.>) :: forall x xs y ys m.
   ( ys ~ Filter x xs
   , Monad m
   , Popable x xs
   ) => Variant xs -> (x -> m y) -> Flow m (y ': ys)
(%~.>) = (?~.>)
infixl 0 %~.>
(>%~.>) ::
   ( ys ~ Filter x xs
   , Monad m
   , Popable x xs
   ) => Flow m xs -> (x -> m y) -> Flow m (y ': ys)
(>%~.>) = liftm (%~.>)
infixl 0 >%~.>
(?~+>) :: forall x xs ys m.
   ( Monad m
   , MaybePopable x xs
   , KnownNat (Length ys)
   ) => Variant xs -> (x -> Flow m ys) -> Flow m (Concat ys (Filter x xs))
(?~+>) v f = case popVariantMaybe v of
   Right x -> appendVariant  @(Filter x xs) <$> f x
   Left ys -> prependVariant @ys            <$> return ys
infixl 0 ?~+>
(>?~+>) :: forall x xs ys m.
   ( Monad m
   , MaybePopable x xs
   , KnownNat (Length ys)
   ) => Flow m xs -> (x -> Flow m ys) -> Flow m (Concat ys (Filter x xs))
(>?~+>) = liftm (?~+>)
infixl 0 >?~+>
(%~+>) :: forall x xs ys m.
   ( Monad m
   , Popable x xs
   , KnownNat (Length ys)
   ) => Variant xs -> (x -> Flow m ys) -> Flow m (Concat ys (Filter x xs))
(%~+>) = (?~+>)
infixl 0 %~+>
(>%~+>) :: forall x xs ys m.
   ( Monad m
   , Popable x xs
   , KnownNat (Length ys)
   ) => Flow m xs -> (x -> Flow m ys) -> Flow m (Concat ys (Filter x xs))
(>%~+>) = liftm (%~+>)
infixl 0 >%~+>
(?~^^>) :: forall x xs ys zs m.
   ( Monad m
   , MaybePopable x xs
   , Liftable (Filter x xs) zs
   , Liftable ys zs
   ) => Variant xs -> (x -> Flow m ys) -> Flow m zs
(?~^^>) v f = case popVariantMaybe v of
   Right x -> liftVariant <$> f x
   Left ys -> liftVariant <$> return ys
infixl 0 ?~^^>
(>?~^^>) :: forall x xs ys zs m.
   ( Monad m
   , MaybePopable x xs
   , Liftable (Filter x xs) zs
   , Liftable ys zs
   ) => Flow m xs -> (x -> Flow m ys) -> Flow m zs
(>?~^^>) = liftm (?~^^>)
infixl 0 >?~^^>
(%~^^>) :: forall x xs ys zs m.
   ( Monad m
   , Popable x xs
   , Liftable (Filter x xs) zs
   , Liftable ys zs
   ) => Variant xs -> (x -> Flow m ys) -> Flow m zs
(%~^^>) = (?~^^>)
infixl 0 %~^^>
(>%~^^>) :: forall x xs ys zs m.
   ( Monad m
   , Popable x xs
   , Liftable (Filter x xs) zs
   , Liftable ys zs
   ) => Flow m xs -> (x -> Flow m ys) -> Flow m zs
(>%~^^>) = liftm (%~^^>)
infixl 0 >%~^^>
(?~^>) :: forall x xs zs m.
   ( Monad m
   , MaybePopable x xs
   , Liftable (Filter x xs) zs
   ) => Variant xs -> (x -> Flow m zs) -> Flow m zs
(?~^>) v f = case popVariantMaybe v of
   Right x -> f x
   Left ys -> return (liftVariant ys)
infixl 0 ?~^>
(>?~^>) :: forall x xs zs m.
   ( Monad m
   , MaybePopable x xs
   , Liftable (Filter x xs) zs
   ) => Flow m xs -> (x -> Flow m zs) -> Flow m zs
(>?~^>) = liftm (?~^>)
infixl 0 >?~^>
(%~^>) :: forall x xs zs m.
   ( Monad m
   , Popable x xs
   , Liftable (Filter x xs) zs
   ) => Variant xs -> (x -> Flow m zs) -> Flow m zs
(%~^>) = (?~^>)
infixl 0 %~^>
(>%~^>) :: forall x xs zs m.
   ( Monad m
   , Popable x xs
   , Liftable (Filter x xs) zs
   ) => Flow m xs -> (x -> Flow m zs) -> Flow m zs
(>%~^>) = liftm (%~^>)
infixl 0 >%~^>
(?~$>) :: forall x xs m.
   ( Monad m
   , MaybePopable x xs
   ) => Variant xs -> (x -> Flow m xs) -> Flow m xs
(?~$>) v f = case popVariantMaybe v of
   Right x -> f x
   Left _  -> return v
infixl 0 ?~$>
(>?~$>) :: forall x xs m.
   ( Monad m
   , MaybePopable x xs
   ) => Flow m xs -> (x -> Flow m xs) -> Flow m xs
(>?~$>) = liftm (?~$>)
infixl 0 >?~$>
(%~$>) :: forall x xs m.
   ( Monad m
   , Popable x xs
   ) => Variant xs -> (x -> Flow m xs) -> Flow m xs
(%~$>) = (?~$>)
infixl 0 %~$>
(>%~$>) :: forall x xs m.
   ( Monad m
   , Popable x xs
   ) => Flow m xs -> (x -> Flow m xs) -> Flow m xs
(>%~$>) = liftm (%~$>)
infixl 0 >%~$>
(?~|>) :: forall x xs ys zs m.
   ( Monad m
   , MaybePopable x xs
   , Liftable (Filter x xs) zs
   , Liftable ys zs
   , zs ~ Union (Filter x xs) ys
   ) => Variant xs -> (x -> Flow m ys) -> Flow m zs
(?~|>) v f = case popVariantMaybe v of
   Right x -> liftVariant <$> f x
   Left ys -> return (liftVariant ys)
infixl 0 ?~|>
(>?~|>) :: forall x xs ys zs m.
   ( Monad m
   , MaybePopable x xs
   , Liftable (Filter x xs) zs
   , Liftable ys zs
   , zs ~ Union (Filter x xs) ys
   ) => Flow m xs -> (x -> Flow m ys) -> Flow m zs
(>?~|>) = liftm (?~|>)
infixl 0 >?~|>
(%~|>) :: forall x xs ys zs m.
   ( Monad m
   , Popable x xs
   , Liftable (Filter x xs) zs
   , Liftable ys zs
   , zs ~ Union (Filter x xs) ys
   ) => Variant xs -> (x -> Flow m ys) -> Flow m zs
(%~|>) = (?~|>)
infixl 0 %~|>
(>%~|>) :: forall x xs ys zs m.
   ( Monad m
   , Popable x xs
   , Liftable (Filter x xs) zs
   , Liftable ys zs
   , zs ~ Union (Filter x xs) ys
   ) => Flow m xs -> (x -> Flow m ys) -> Flow m zs
(>%~|>) = liftm (%~|>)
infixl 0 >%~|>
(?~=>) :: forall x xs m.
   ( Monad m
   , MaybePopable x xs
   ) => Variant xs -> (x -> m ()) -> Flow m xs
(?~=>) v f = case popVariantMaybe v of
   Right x -> f x >> return v
   Left _  -> return v
infixl 0 ?~=>
(>?~=>) :: forall x xs m.
   ( Monad m
   , MaybePopable x xs
   ) => Flow m xs -> (x -> m ()) -> Flow m xs
(>?~=>) = liftm (?~=>)
infixl 0 >?~=>
(%~=>) :: forall x xs m.
   ( Monad m
   , Popable x xs
   ) => Variant xs -> (x -> m ()) -> Flow m xs
(%~=>) = (?~=>)
infixl 0 %~=>
(>%~=>) :: forall x xs m.
   ( Monad m
   , Popable x xs
   ) => Flow m xs -> (x -> m ()) -> Flow m xs
(>%~=>) = liftm (%~=>)
infixl 0 >%~=>
(?~!>) :: forall x xs m.
   ( Monad m
   , MaybePopable x xs
   ) => Variant xs -> (x -> m ()) -> m ()
(?~!>) v f = case popVariantMaybe v of
   Right x -> f x
   Left _  -> return ()
infixl 0 ?~!>
(>?~!>) :: forall x xs m.
   ( Monad m
   , MaybePopable x xs
   ) => Flow m xs -> (x -> m ()) -> m ()
(>?~!>) = liftm (?~!>)
infixl 0 >?~!>
(%~!>) :: forall x xs m.
   ( Monad m
   , Popable x xs
   ) => Variant xs -> (x -> m ()) -> m ()
(%~!>) = (?~!>)
infixl 0 %~!>
(>%~!>) :: forall x xs m.
   ( Monad m
   , Popable x xs
   ) => Flow m xs -> (x -> m ()) -> m ()
(>%~!>) = liftm (%~!>)
infixl 0 >%~!>
(?~!!>) :: forall x xs m.
   ( Monad m
   , MaybePopable x xs
   ) => Variant xs -> (x -> m ()) -> Flow m (Filter x xs)
(?~!!>) v f = case popVariantMaybe v of
   Right x -> f x >> error "?~!!> error"
   Left u  -> return u
infixl 0 ?~!!>
(>?~!!>) :: forall x xs m.
   ( Monad m
   , MaybePopable x xs
   ) => Flow m xs -> (x -> m ()) -> Flow m (Filter x xs)
(>?~!!>) = liftm (?~!!>)
infixl 0 >?~!!>
(%~!!>) :: forall x xs m.
   ( Monad m
   , Popable x xs
   ) => Variant xs -> (x -> m ()) -> Flow m (Filter x xs)
(%~!!>) = (?~!!>)
infixl 0 %~!!>
(>%~!!>) :: forall x xs m.
   ( Monad m
   , Popable x xs
   ) => Flow m xs -> (x -> m ()) -> Flow m (Filter x xs)
(>%~!!>) = liftm (%~!!>)
infixl 0 >%~!!>
makeFlowOp :: Monad m =>
      (Variant as -> Either (Variant bs) (Variant cs))
      -> (Variant cs -> Flow m ds)
      -> (Either (Variant bs) (Variant ds) -> es)
      -> Variant as -> m es
makeFlowOp select apply combine v = combine <$> traverse apply (select v)
makeFlowOpM :: Monad m =>
      (Variant as -> Either (Variant bs) (Variant cs))
      -> (Variant cs -> Flow m ds)
      -> (Either (Variant bs) (Variant ds) -> es)
      -> Flow m as -> m es
makeFlowOpM select apply combine v = v >>= makeFlowOp select apply combine
selectFirst :: Variant (x ': xs) -> Either (Variant xs) (Variant '[x])
selectFirst = fmap (toVariantAt @0) . popVariantHead
selectTail :: Variant (x ': xs) -> Either (Variant '[x]) (Variant xs)
selectTail = flipEither . selectFirst
   where
      flipEither (Left x)  = Right x
      flipEither (Right x) = Left x
selectType ::
   ( Popable x xs
   ) => Variant xs -> Either (Variant (Filter x xs)) (Variant '[x])
selectType = fmap (toVariantAt @0) . popVariant
applyConst :: Flow m ys -> (Variant xs -> Flow m ys)
applyConst = const
applyPure :: Monad m => (Variant xs -> Variant ys) -> Variant xs -> Flow m ys
applyPure f = return . f
applyM :: Monad m => (a -> m b) -> Variant '[a] -> Flow m '[b]
applyM = liftF
applyVM :: Monad m => (Variant a -> m b) -> Variant a -> Flow m '[b]
applyVM f = fmap (toVariantAt @0) . f
applyF :: (a -> Flow m b) -> Variant '[a] -> Flow m b
applyF f = f . variantToValue
combineFirst :: forall x xs. Either (Variant xs) (Variant '[x]) -> Variant (x ': xs)
combineFirst = \case
   Right x -> appendVariant  @xs x
   Left xs -> prependVariant @'[x] xs
combineSameTail :: forall x xs.
   Either (Variant xs) (Variant (x ': xs)) -> Variant (x ': xs)
combineSameTail = \case
   Right x -> x
   Left xs -> prependVariant @'[x] xs
combineEither :: Either (Variant xs) (Variant xs) -> Variant xs
combineEither = \case
   Right x -> x
   Left x  -> x
combineConcat :: forall xs ys.
   ( KnownNat (Length xs)
   ) => Either (Variant ys) (Variant xs) -> Variant (Concat xs ys)
combineConcat = \case
   Right xs -> appendVariant  @ys xs
   Left ys  -> prependVariant @xs ys
combineUnion ::
   ( Liftable xs (Union xs ys)
   , Liftable ys (Union xs ys)
   ) => Either (Variant ys) (Variant xs) -> Variant (Union xs ys)
combineUnion = \case
   Right xs -> liftVariant xs
   Left  ys -> liftVariant ys
combineLiftUnselected ::
   ( Liftable ys xs
   ) => Either (Variant ys) (Variant xs) -> Variant xs
combineLiftUnselected = \case
   Right xs -> xs
   Left ys  -> liftVariant ys
combineLiftBoth ::
   ( Liftable ys zs
   , Liftable xs zs
   ) => Either (Variant ys) (Variant xs) -> Variant zs
combineLiftBoth = \case
   Right xs -> liftVariant xs
   Left ys  -> liftVariant ys
combineSingle :: Either (Variant '[x]) (Variant '[x]) -> x
combineSingle = \case
   Right x -> variantToValue x
   Left  x -> variantToValue x
liftV :: (a -> b) -> Variant '[a] -> Variant '[b]
liftV = updateVariantAt @0
liftF :: Monad m => (a -> m b) -> Variant '[a] -> Flow m '[b]
liftF = updateVariantFirstM @0