content: {-# LANGUAGE Trustworthy #-} -- Safe if eliminate GeneralizedNewtypeInstance
  {-# LANGUAGE Arrows #-}
  {-# LANGUAGE RankNTypes #-}
  {-# LANGUAGE BangPatterns #-}
  {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE UndecidableInstances #-}
  {-# LANGUAGE MultiParamTypeClasses #-}
  {-# LANGUAGE LambdaCase #-}
  {-# LANGUAGE RecordWildCards #-}
  {-# LANGUAGE MultiWayIf #-}
  {-# LANGUAGE TupleSections #-}
  {-# LANGUAGE GADTs #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  
  module
      Control.Arrow.Machine.Types
  where
  
  import qualified Control.Category as Cat
  import Data.Profunctor (Profunctor, dimap, rmap)
  import Control.Arrow
  import Control.Monad
  import Control.Monad.Trans
  import Control.Monad.State
  import Control.Monad.Reader
  import Control.Monad.Writer hiding ((<>))
  import Control.Monad.Identity
  import Control.Applicative
  import Data.Foldable as Fd
  import Data.Traversable as Tv
  import Data.Semigroup (Semigroup, (<>))
  import Data.Maybe (fromMaybe, isNothing, isJust)
  import qualified Control.Monad.Trans.Free as F
  import qualified Control.Monad.Trans.Free.Church as F
  import Control.Arrow.Machine.ArrowUtil
  import GHC.Exts (build)
  
  
  -- | To get multiple outputs by one input, the `Phase` parameter is introduced.
  --
  -- Once a value `Feed`ed, the machine is `Sweep`ed until it `Suspend`s.
  data Phase = Feed | Sweep | Suspend deriving (Eq, Show)
  
  instance
      Monoid Phase
    where
      mempty = Sweep
  
      mappend Feed _ = Feed
      mappend _ Feed = Feed
      mappend Suspend _ = Suspend
      mappend _ Suspend = Suspend
      mappend Sweep Sweep = Sweep
  
  
  type ProcType a b c = ProcessA a b c
  
  -- | The stream transducer arrow.
  --
  -- To construct `ProcessA` instances, use `Control.Arrow.Machine.Plan.Plan`,
  -- `arr`, functions declared in `Control.Arrow.Machine.Utils`,
  -- or arrow combinations of them.
  --
  -- See an introduction at "Control.Arrow.Machine" documentation.
  data ProcessA a b c = ProcessA {
      feed :: a b (c, ProcessA a b c),
      sweep :: a b (Maybe c, ProcessA a b c),
      suspend :: !(b -> c)
    }
  
  
  -- For internal use
  class
      (Applicative f, Monad f) => ProcessHelper f
    where
      step :: ArrowApply a => ProcessA a b c -> a b (f c, ProcessA a b c)
      helperToMaybe :: f a -> Maybe a
      weakly :: a -> f a
  
      step' :: ArrowApply a => ProcessA a b c -> a (f b) (f c, ProcessA a b c)
      step' pa = proc hx ->
        do
          let mx = helperToMaybe hx
          maybe
              (arr $ const (suspend pa <$> hx, pa))
              (\x -> proc _ -> step pa -< x)
              mx
                  -<< ()
  
  