# LANGUAGE CPP #
{-# LANGUAGE DeriveDataTypeable #-}
# LANGUAGE ExistentialQuantification #
{-# LANGUAGE RankNTypes #-}
# LANGUAGE TupleSections #
# OPTIONS_HADDOCK not - home #

-- |
-- Module      : Control.Auto.Core
-- Description : Core types, constructors, and utilities.
-- Copyright   : (c) Justin Le 2015
  License      : MIT
  Maintainer   : 
-- Stability   : unstable
-- Portability : portable
--
-- This module defines and provides the core types, (smart) constructors,
-- and general high and low-level utilities used by the /auto/ library.
--
-- Note that importing and using functions from this module in part voids
-- some of the "semantic contracts" of the 'Auto' types you get, so use
-- with caution!
--
-- A lot of low-level functionality is provided here which is most likely
-- unnecessary for most applications; many are mostly for internal usage or
-- advanced/fine-grained usage.  It also isn't really enough to do too many
-- useful things, either.  It's recommended that you import "Control.Auto"
-- instead, which re-organizes the more useful parts of this module in
-- addition with useful parts of others to provide a nice packaged entry
-- point.  If something in here becomes useful for more than just
-- fine-tuning or low-level tweaking, it is probably supposed to be in
-- "Control.Auto" anyway.
--
-- Information on how to use these types is available in the
-- < tutorial>!
--

module Control.Auto.Core (
  -- * Auto
  -- ** Type
    Auto
  , Auto'
  , autoConstr
  , toArb
  , purifyAuto
  -- ** Running
  , stepAuto
  , stepAuto'
  , evalAuto
  , evalAuto'
  , execAuto
  , execAuto'
  * * 
  -- $serializing
  , encodeAuto
  , decodeAuto
  , saveAuto
  , resumeAuto
  , unserialize
  -- ** Underlying monad
  , hoistA
  , generalizeA
  -- ** Special modifiers
  , interceptO
  -- * Auto constructors
  -- ** Lifting values and functions
  , mkConst
  , mkConstM
  , mkFunc
  , mkFuncM
  * * from State transformers
  , mkState
  , mkState_
  , mkStateM
  , mkStateM_
  , mkState'
  , mkStateM'
  -- ** from Accumulators
  -- *** Result-first
  , accum
  , accum_
  , accumM
  , accumM_
  -- *** Initial accumulator-first
  , accumD
  , accumD_
  , accumMD
  , accumMD_
  -- ** Arbitrary Autos
  , mkAuto
  , mkAuto_
  , mkAutoM
  , mkAutoM_
  -- * Strictness
  , forceSerial
  , forcer
  , seqer
  ) where

import Control.Applicative
import Control.Arrow
import Control.Category
import Control.DeepSeq
import Control.Monad hiding   (sequence)
import Control.Monad.Fix
import Data.ByteString hiding (empty)
import Data.Functor.Identity
import Data.Orphans           ()
import Data.Profunctor
import Data.Semigroup
import Data.Serialize
import Data.String
import Data.Traversable
import Prelude hiding         ((.), id, sequence)

#if MIN_VERSION_base(4,7,0)
import Data.Typeable
#endif


-- | The 'Auto' type.  For this library, an 'Auto' semantically
  represents / denotes a /a relationship/ between an input and an
-- output that is preserved over multiple steps, where that relationship is
-- (optionally) maintained within the context of a monad.
--
-- A lot of fancy words, I know...but you can think of an 'Auto' as nothing
-- more than a "stream transformer" of value streams.  A stream of
-- sequential input values come in one at a time, and a stream of outputs
-- pop out one at a time, as well.
--
-- Using the 'streamAuto' function, you can "unwrap" the inner value stream
  transformer from any ' Auto ' : if @a : : ' Auto ' m a b@ , ' streamAuto ' lets
  you turn it into an @[a ] - > m [ b]@.   " Give me a stream of @a@s , one at
-- a time, and I'll give you a list of @b@s, matching a relationship to
  your stream of @a@s . "
--
-- @
-- -- unwrap your inner [a] -> m [b]!
  ' streamAuto ' : :   = > ' Auto ' m a b - > ( [ a ] - > m [ b ] )
-- @
--
-- You can also turn an @'Auto' m a b@ into an /effects stream/ that
-- executes effects sequentially with 'toEffectStream' and
-- 'streamAutoEffects', so you can run it with a ListT-compatible library
-- like /pipes/.
--
-- There's a handy type synonym 'Auto'' for relationships that don't really
-- need a monadic context; the @m@ is just 'Identity':
--
-- @
  type Auto ' = Auto Identity
-- @
--
  So if you had an @a : : ' Auto '' a b@ , you can use ' streamAuto '' to
  " unwrap " the inner stream transformer , @[a ] - > [ b]@.
--
-- @
-- -- unwrap your inner [a] -> [b]!
-- 'streamAuto'' :: 'Auto'' a b -> ([a] -> [b])
-- @
--
-- All of the 'Auto's given in this library maintain some sort of semantic
-- relationship between streams --- for some, the outputs might be the
-- inputs with a function applied; for others, the outputs might be the
-- cumulative sum of the inputs.
--
-- See the
-- < tutorial>
-- for more information!
--
-- Operationally, an  @'Auto' m a b@ is implemented as a "stateful
-- function".  A function from an @a@ where, every time you "apply" it, you
  get a @b@ and an " updated ' Auto'"/function with updated state .
--
-- You can get this function using 'stepAuto':
--
-- @
-- 'stepAuto' :: 'Auto' m a b -> (a -> m (b, 'Auto' m a b))
-- @
--
-- Or, for 'Auto'', 'stepAuto'':
--
-- @
-- 'stepAuto'' :: 'Auto'' a b -> (a -> (b, 'Auto'' a b))
-- @
--
  " Give me an @a@ and I 'll give you a @b@ and your " updated " ' Auto ' " .
--
-- 'Auto's really are mostly useful because they can be composed, chained,
-- and modified using their various typeclass instances, like 'Category',
  ' Applicative ' , ' Functor ' , ' Arrow ' , etc . , and also with the combinators
-- in this library.  You can build complex programs as a complex 'Auto' by
-- building up smaller and smaller components.  See the tutorial for more
-- information on this.
--
-- This type also contains information on its own serialization, so you can
-- serialize and re-load the internal state to binary or disk.  See the
-- "serialization" section in the documentation for "Control.Auto.Core", or
-- the documentation for 'mkAutoM' for more details.
--
data Auto m a b =           AutoFunc    !(a -> b)
                |           AutoFuncM   !(a -> m b)
                | forall s. AutoState   (Get s, s -> Put) !(a -> s -> (b, s))   !s
                | forall s. AutoStateM  (Get s, s -> Put) !(a -> s -> m (b, s)) !s
                |           AutoArb     (Get (Auto m a b)) Put !(a -> (b, Auto m a b))
                |           AutoArbM    (Get (Auto m a b)) Put !(a -> m (b, Auto m a b))
#if MIN_VERSION_base(4,7,0)
                deriving ( Typeable )
#endif


  | Special case of ' Auto ' where the underlying '  ' is ' Identity ' .
--
  Instead of " wrapping " an @[a ] - > m [  , it " wraps " an @[a ] - > [ b]@.
type Auto'   = Auto Identity


-- | Re-structure 'Auto' internals to use the 'Arb' ("arbitrary")
-- constructors, as recursion-based mealy machines.
--
-- Mostly here for performance comparisons and benchmarking purposes.
--
toArb :: Monad m => Auto m a b -> Auto m a b
toArb a = a_
  where
    a_ = case a of
           AutoFunc f  -> AutoArb  (pure a_)
                                   (return ())
                                 $ \x -> (f x, a_)
           AutoFuncM f -> AutoArbM (pure a_)
                                   (return ())
                                 $ \x -> liftM (, a_) (f x)
           AutoState gp@(g,p) f s  ->
               let a' s' = AutoArb (toArb . AutoState gp f <$> g)
                                   (p s')
                                 $ \x -> let (y, s'') = f x s'
                                         in  (y, a' s'')
               in  a' s
           AutoStateM gp@(g,p) f s ->
               let a' s' = AutoArbM (toArb . AutoStateM gp f <$> g)
                                    (p s)
                                  $ \x -> do
                                      (y, s'') <- f x s'
                                      return (y, a' s'')
               in  a' s
           AutoArb l s f -> AutoArb (toArb <$> l)
                                    s
                                  $ \x -> let (y, a') = f x
                                          in  (y, toArb a')
           AutoArbM l s f -> AutoArbM (toArb <$> l)
                                      s
                                    $ \x -> do
                                        (y, a') <- f x
                                        return (y, toArb a')


-- | Returns a string representation of the internal constructor of the
-- 'Auto'.  Useful for debugging the result of compositions and functions
-- and seeing how they affect the internal structure of the 'Auto'.
--
-- In the order of efficiency, "AutoFunc"s tend to be faster than
-- "AutoState"s tend to be faster than "AutoArb"s.  However, when composing
  one with the other ( using ' Category ' or ' Applicative ' ) , the two have to
  be " reduced " to the greatest common denominator ; composing an " AutoFunc "
  with an " AutoArb " produces an "  " .
--
-- More benchmarking is to be done to be able to rigorously say what these
-- really mean, performance wise.
autoConstr :: Auto m a b -> String
autoConstr (AutoFunc {})   = "AutoFunc"
autoConstr (AutoFuncM {})  = "AutoFuncM"
autoConstr (AutoState {})  = "AutoState"
autoConstr (AutoStateM {}) = "AutoStateM"
autoConstr (AutoArb {})    = "AutoArb"
autoConstr (AutoArbM {})   = "AutoArbM"

  | Swaps out the underlying '  ' of an ' Auto ' using the given monad
-- morphism "transforming function", a natural transformation.
--
-- Basically, given a function to "swap out" any @m a@ with an @m' a@, it
-- swaps out the underlying monad of the 'Auto'.
--
-- This forms a functor, so you rest assured in things like this:
--
-- @
-- hoistA id == id
-- hoistA f a1 . hoistA f a2 == hoistA f (a1 . a2)
-- @
hoistA :: (Monad m, Monad m')
       => (forall c. m c -> m' c)   -- ^ monad morphism;
                                    --     the natural transformation
       -> Auto m a b
       -> Auto m' a b
hoistA _ (AutoFunc f)        = AutoFunc f
hoistA g (AutoFuncM f)       = AutoFuncM (g . f)
hoistA _ (AutoState gp f s)  = AutoState gp f s
hoistA g (AutoStateM gp f s) = AutoStateM gp (\x s' -> g (f x s')) s
hoistA g (AutoArb gt pt f)   = AutoArb (fmap (hoistA g) gt)
                                       pt
                                       $ \x -> let (y, a') = f x
                                               in  (y, hoistA g a')
hoistA g (AutoArbM gt pt f)  = AutoArbM (fmap (hoistA g) gt)
                                        pt
                                        $ \x -> g $ do
                                            (y, a') <- f x
                                            return (y, hoistA g a')

-- | Generalizes an @'Auto'' a b@ to an @'Auto' m a b'@ for any 'Monad'
-- @m@, using 'hoist'.
--
-- You generally should be able to avoid using this if you never directly
-- write any 'Auto''s and always write 'Auto m' parameterized over all
  ' Monad 's , but ... in case you import one from a library or something , you
-- can use this.
--
generalizeA :: Monad m => Auto' a b -> Auto m a b
generalizeA = hoistA (return . runIdentity)

-- | Force the serializing components of an 'Auto'.
--
-- TODO: Test if this really works
forceSerial :: Auto m a b -> Auto m a b
forceSerial a = case a of
                  AutoArb _ l s  -> l `seq` s `seq` a
                  AutoArbM _ l s -> l `seq` s `seq` a
                  _              -> a

-- $serializing
--
-- The 'Auto' type offers an interface in which you can serialize
  ( " freeze " ) and " resume " an Auto , in ' ByteString ' ( binary ) form .
--
-- You can "freeze" any 'Auto' into a 'ByteString' using 'encodeAuto' (or,
  if you want the raw ' Put ' ( from " Data . Serialize " ) for some reason ,
-- there's 'saveAuto'.
--
-- You can "resume" any 'Auto' from a 'ByteString' using 'decodeAuto' (or,
-- if you want the raw 'Get' for some reason, there's 'resumeAuto').
--
  Note ' decodeAuto ' and ' resumeAuto ' " resume " a  ' Auto'/.   That is ,
-- if you call 'decodeAuto' on a "fresh 'Auto'", it'll decode
-- a 'ByteString' into /that 'Auto', but "resumed"/.  That is, it'll "fast
-- forward" that 'Auto' into the state it was when it was saved.
--
  For example , let 's say I have @a = ' sumFrom ' 0@ , the ' Auto ' whose output
  is the cumulative sum of all of its inputs so far . If I feed it 3 and
  10 , it 'll have its internal accumulator as 13 , keeping track of all the
-- numbers it has seen so far.
--
-- >>> let a = sumFrom 0
  > > > let ( _ , a ' ) = stepAuto ' a   3
-- >>> let (_, a'') = stepAuto' a' 10
--
  I can then use ' encodeAuto ' to " freeze"/"save " the ' Auto ' into the
  ' ByteString ' @bs@ :
--
-- >>> let bs            = encodeAuto a''
--
-- To "resume" / "load" it, I can use 'decodeAuto' to "resume" the
      , ' a ' was our original ' Auto ' , the summer
  ' Auto ' with a starting accumulator of 0 .   We use ' decodeAuto ' to
  " resume " it , with and resume it with its internal accumulator at 13 .
--
-- >>> let (Right resumed) = decodeAuto a bs
  > > > let ( y , _ ) = stepAuto ' resumed 0
  13
--
-- Note that all of these would have had the same result:
--
-- >>> let (Right resumed) = decodeAuto a'  bs
-- >>> let (Right resumed) = decodeAuto a'' bs
-- >>> let (Right resumed) = decodeAuto (sumFrom 0) bs
--
-- I mean, after all, if 'decodeAuto' "fast forwards" an 'Auto' to the
-- state it was at when it was frozen...then all of these should really be
-- resumed to the same point, right?
--
  One way you can think about it is that ' resumeAuto ' / ' decodeAuto ' takes
-- an 'Auto' and creates a "blueprint" from that 'Auto', on how to "load
-- it"; the blueprint contains what the form of the internal state is, and
-- their offets in the 'ByteString'.  So in the above, 'a', 'a'', 'a''',
-- and @'sumFrom' 0@ all have the same "blueprint" --- their internal
-- states are of the same structure.
--
-- Now, the /magic/ of this all is that combining and transforming 'Auto's
-- with the combinators in this library will also /compose serialization
-- strategies/ .... complex 'Auto's and combinations/chains of 'Auto's
-- create serialization strategies "for free".  The
-- <-examples auto-examples> repo has a lot
-- of examples that use this  to great effect, serializing entire
-- applications and entire chat bots without writing any serialization
-- code; it all does it "by itself".  Be sure to read about the caveats in
-- the
-- < tutorial>.
--
-- Some specific 'Auto's (indicated by a naming convention) might choose to
-- have internal state, yet ignore it when saving/loading.  So, saving it
-- actaully saves no state, and "resuming" it really doesn't do anything.
-- That is, @'decodeAuto' a_ bs = Right a_@.  There isn't a real way to
-- identify from the type of the 'Auto' if it will properly save/resume or
-- not, so you have to keep track of this yourself.  In all of the 'Auto'
  " included " in this library , any ' Auto ' whose name /does not/ end in @_@
  /will serialize and resume/.   An ' Auto ' whose name ends in @_@ is taken
-- by naming convention to be a non-resuming 'Auto'.
--
-- In your own compositions, if you are sure to always use resuming
-- 'Auto's, your composition will also be properly resuming...so you don't
-- have to worry about this!  You shouldn't really ever be "surprised",
-- because you'll always explicitly chose the resuming version for 'Auto's
-- you want to resume, and the non-resuming version for those you don't.
--
-- Now, /making/ or /writing/ your own generic 'Auto' combinators and
-- transformers that take advantage of serialization is a bit of
-- a headache.  When you can, you might be able to make combinators out of
-- the existing functions in this library.  Sometimes, however, it's
-- unavoidable.  If you are making your own 'Auto' combinators, making sure
-- serialization works as expected is tough; check out the documentation
-- for 'mkAutoM' for more details.
--

-- | Encode an 'Auto' and its internal state into a 'ByteString'.
encodeAuto :: Auto m a b -> ByteString
encodeAuto = runPut . saveAuto
# INLINE encodeAuto #

  | " Resume " an ' Auto ' from its ' ByteString ' serialization , giving
-- a 'Left' if the deserialization is not possible.
decodeAuto :: Auto m a b -> ByteString -> Either String (Auto m a b)
decodeAuto = runGet . resumeAuto
# INLINE decodeAuto #

-- | Returns a 'Get' from an 'Auto' ---  instructions (from
  " Data . Serialize " ) on taking a ByteString and " restoring " the originally
-- saved 'Auto', in the originally saved state.
resumeAuto :: Auto m a b -> Get (Auto m a b)
resumeAuto a = case a of
                 AutoState gp f _  -> AutoState  gp f <$> fst gp
                 AutoStateM gp f _ -> AutoStateM gp f <$> fst gp
                 AutoArb g _ _     -> g
                 AutoArbM g _ _    -> g
                 _                 -> return a
# INLINE resumeAuto #

  | Returns a ' Put ' --- instructions ( from " Data . Serialize " ) on how to
  " freeze " the ' Auto ' , with its internal state , and save it to a binary
-- encoding.  It can later be reloaded and "resumed" by
-- 'resumeAuto'/'decodeAuto'.
saveAuto :: Auto m a b -> Put
saveAuto a = case a of
               AutoState (_, p) _ s  -> p s
               AutoStateM (_, p) _ s -> p s
               AutoArb _ p _         -> p
               AutoArbM _ p _        -> p
               _                     -> return ()
# INLINE saveAuto #

-- | Takes an 'Auto' that is serializable/resumable and returns an 'Auto'
-- that is not.  That is, when it is "saved", saves no data, and when it is
-- "resumed", resets itself back to the initial configuration every time;
-- in other words, @'decodeAuto' (unserialize a) bs = Right (unserialize
-- a)@.  Trying to "resume" it will just always give itself, unchanged.
unserialize :: Monad m => Auto m a b -> Auto m a b
unserialize a =
    case a of
        AutoFunc _       -> a
        AutoFuncM _      -> a
        AutoState _ f s  -> AutoState (pure s, const (put ())) f s
        AutoStateM _ f s -> AutoStateM (pure s, const (put ())) f s
        AutoArb _ _ f    -> AutoArb (pure a) (put ()) (second unserialize . f)
        AutoArbM _ _ f   -> AutoArbM (pure a) (put ()) (liftM (second unserialize) . f)

  | " Runs " the ' Auto ' through one step .
--
-- That is, given an @'Auto' m a b@, returns a function that takes an @a@
  and returns a @b@ and an " updated"/"next " ' Auto ' ; an @a - > m ( b , ' Auto '
  m a b)@.
--
-- This is the main way of running an 'Auto' "step by step", so if you have
-- some sort of game loop that updates everything every "tick", this is
-- what you're looking for.  At every loop, gather input @a@, feed it into
  the ' Auto ' , " render " the result @b@ , and get your new ' Auto ' to run the
-- next time.
--
  Here is an example with @'sumFrom ' 0@ , the ' Auto ' whose output is the
  cumulative sum of the inputs , and an underying monad of 
-- Here,
--
-- @
-- stepAuto :: Auto Identity Int Int
--          -> (Int -> Identity (Int, Auto Identity Int Int))
-- @
--
-- Every time you "step", you give it an 'Int' and get a resulting 'Int'
-- (the cumulative sum) and the "updated 'Auto'", with the updated
-- accumulator.
--
  > > > let a0 : : Auto Identity Int Int
--         a0 = sumFrom 0
  > > > let Identity ( res1 , a1 ) = stepAuto a0 4       -- run with 4
-- >>> res1
  4                 -- the cumulative sum , 4
  > > > let Identity ( res2 , a2 ) = stepAuto a1 5       -- run with 5
-- >>> res2
  9                 -- the cumulative sum , 4 + 5
  > > > let Identity ( res3 , _ ) = stepAuto a2 3       -- run with 3
-- >>> res3
  12                -- the cumulative sum , 4 + 5 + 3
--
-- By the way, for the case where your 'Auto' is under 'Identity', we have
-- a type synomym 'Auto''...and a convenience function to make "running" it
-- more streamlined:
--
-- >>> let a0 :: Auto' Int Int
--         a0 = sumFrom 0
  > > > let ( res1 , a1 ) = stepAuto ' a0 4           -- run with 4
-- >>> res1
  4                 -- the cumulative sum , 4
  > > > let ( res2 , a2 ) = stepAuto ' a1 5           -- run with 5
-- >>> res2
  9                 -- the cumulative sum , 4 + 5
  > > > let ( res3 , _ ) = stepAuto ' a2 3           -- run with 3
-- >>> res3
  12                -- the cumulative sum , 4 + 5 + 3
--
-- But, if your 'Auto' actaully has effects when being stepped, 'stepAuto'
-- will execute them:
--
-- >>> let a0 :: Auto IO Int Int
--         a0 = effect (putStrLn "hey!") *> sumFrom 0
  > > > ( res1 , a1 ) < - stepAuto a0 4               -- run with 4
-- hey!         -- IO effect
-- >>> res1
  4                 -- the cumulative sum , 4
  > > > ( res2 , a2 ) < - stepAuto a1 5               -- run with 5
-- hey!         -- IO effect
-- >>> res2
  9                 -- the cumulative sum , 4 + 5
  > > > ( res3 , _ ) < - stepAuto a2 3               -- run with 3
-- hey!         -- IO effect
-- >>> res3
  12                -- the cumulative sum , 4 + 5 + 3
--
  ( Here , @'effect ' ( ' putStrLn ' " hey")@ is an @'Auto ' IO Int ( ) @ , which
-- ignores its input and just executes @'putStrLn' "hey"@ every time it is
  run .   When we use ' * > ' from " Control . Applicative " , we " combine " the two
  ' Auto 's together and run them /both/ on each input ( 4 , 5 , 3 ... ) ... but
-- for the "final" output at the end, we only return the output of the
  second one , @'sumFrom ' 0@ ( 5 , 9 , 12 ... ) )
--
  If you think of an @'Auto ' m a b@ as a " stateful function " @a - > m b@ ,
-- then 'stepAuto' lets you "run" it.
--
  In order to directly run an ' Auto ' on a stream , an @[a]@ , use
  ' streamAuto ' .   That gives you an @[a ] - > m [ b]@.
--
stepAuto :: Monad m
         => Auto m a b        -- ^ the 'Auto' to step
         -> a                 -- ^ the input
         -> m (b, Auto m a b) -- ^ the output, and the updated 'Auto''.
stepAuto a x = case a of
                 AutoFunc f        ->
                     return (f x, a)
                 AutoFuncM f       -> do
                     y <- f x
                     return (y, a)
                 AutoState gp f s  ->
                     let (y, s') = f x s
                         a'      = AutoState gp f s'
                     in  return (y, a')
                 AutoStateM gp f s -> do
                     (y, s') <- f x s
                     let a' = AutoStateM gp f s'
                     return (y, a')
                 AutoArb _ _ f     -> return (f x)
                 AutoArbM _ _ f    -> f x
# INLINE stepAuto #

  | " Runs " an ' Auto '' through one step .
--
-- That is, given an @'Auto'' a b@, returns a function that takes an @a@
  and returns a @b@ and an " updated"/"next " ' Auto '' ; an @a - > ( b , ' Auto ''
  a b)@.
--
-- See 'stepAuto' documentation for motivations, use cases, and more
-- details.  You can use this instead of 'stepAuto' when your underyling
-- monad is 'Identity', and your 'Auto' doesn't produce any effects.
--
  Here is an example with @'sumFrom ' 0@ , the ' Auto '' whose output is the
-- cumulative sum of the inputs
--
-- @
-- stepAuto' :: Auto' Int Int
--           -> (Int -> (Int, Auto' Int Int))
-- @
--
-- Every time you "step", you give it an 'Int' and get a resulting 'Int'
-- (the cumulative sum) and the "updated 'Auto''", with the updated
-- accumulator.
--
-- >>> let a0 :: Auto' Int Int
--         a0 = sumFrom 0
  > > > let ( res1 , a1 ) = stepAuto ' a0 4           -- run with 4
-- >>> res1
  4                 -- the cumulative sum , 4
  > > > let ( res2 , a2 ) = stepAuto ' a1 5           -- run with 5
-- >>> res2
  9                 -- the cumulative sum , 4 + 5
  > > > let ( res3 , _ ) = stepAuto ' a2 3           -- run with 3
-- >>> res3
  12                -- the cumulative sum , 4 + 5 + 3
--
-- If you think of an @'Auto'' a b@ as a "stateful function" @a -> b@,
-- then 'stepAuto'' lets you "run" it.
--
  In order to directly run an ' Auto '' on a stream , an @[a]@ , use
  ' streamAuto '' .   That gives you an @[a ] - > [ b]@.
--
stepAuto' :: Auto' a b        -- ^ the 'Auto'' to step
          -> a                -- ^ the input
          -> (b, Auto' a b)   -- ^ the output, and the updated 'Auto''
stepAuto' a x = case a of
                  AutoFunc f        -> (f x, a)
                  AutoFuncM f       -> (runIdentity (f x), a)
                  AutoState gp f s  -> let (y, s') = f x s
                                           a'      = AutoState gp f s'
                                       in  (y, a')
                  AutoStateM gp f s -> let (y, s') = runIdentity (f x s)
                                           a'      = AutoStateM gp f s'
                                       in  (y, a')
                  AutoArb _ _ f     -> f x
                  AutoArbM _ _ f    -> runIdentity (f x)
# INLINE stepAuto ' #

-- | In theory, "purifying" an 'Auto''" should prep it for faster
-- evaluation when used with 'stepAuto'' or 'streamAuto''.  But the
-- benchmarks have not been run yet, so stay tuned!
--
-- TODO: Benchmark
purifyAuto :: Auto' a b -> Auto' a b
purifyAuto a@(AutoFunc {})     = a
purifyAuto (AutoFuncM f)       = AutoFunc (runIdentity . f)
purifyAuto a@(AutoState {})    = a
purifyAuto (AutoStateM gp f s) = AutoState gp (\x s' -> runIdentity (f x s')) s
purifyAuto (AutoArb g p f)     = AutoArb (purifyAuto <$> g)
                                         p
                                       $ \x -> let (y, a') = f x
                                               in  (y, purifyAuto a')
purifyAuto (AutoArbM g p f)    = AutoArb (purifyAuto <$> g)
                                         p
                                       $ \x -> let (y, a') = runIdentity (f x)
                                               in  (y, purifyAuto a')

-- | Like 'stepAuto', but drops the "next 'Auto'" and just gives the
-- result.
evalAuto :: Monad m
         => Auto m a b      -- ^ 'Auto' to run
         -> a               -- ^ input
         -> m b             -- ^ output
evalAuto a = liftM fst . stepAuto a

-- | Like 'stepAuto'', but drops the "next 'Auto''" and just gives the
-- result.  'evalAuto' for 'Auto''.
evalAuto' :: Auto' a b      -- ^ 'Auto' to run
          -> a              -- ^ input
          -> b              -- ^ output
evalAuto' a = fst . stepAuto' a

-- | Like 'stepAuto', but drops the result and just gives the "updated
-- 'Auto'".
execAuto :: Monad m
         => Auto m a b      -- ^ 'Auto' to run
         -> a               -- ^ input
         -> m (Auto m a b)  -- ^ updated 'Auto'
execAuto a = liftM snd . stepAuto a

-- | Like 'stepAuto'', but drops the result and just gives the "updated
-- 'Auto''".  'execAuto' for 'Auto''.
execAuto' :: Auto' a b      -- ^ 'Auto'' to run
          -> a              -- ^ input
          -> Auto' a b      -- ^ updated 'Auto''
execAuto' a = snd . stepAuto' a

-- | A special 'Auto' that acts like the 'id' 'Auto', but forces results as
-- they come through to be fully evaluated, when composed with other
-- 'Auto's.
--
-- TODO: Test if this really works
forcer :: NFData a => Auto m a a
forcer = mkAuto_ $ \x -> x `deepseq` (x, forcer)
# INLINE forcer #

-- | A special 'Auto' that acts like the 'id' 'Auto', but forces results as
-- they come through to be evaluated to Weak Head Normal Form, with 'seq',
-- when composed with other 'Auto's.
--
-- TODO: Test if this really works
seqer :: Auto m a a
seqer = mkAuto_ $ \x -> x `seq` (x, seqer)
# INLINE seqer #

-- | Abstraction over lower-level funging with serialization; lets you
-- modify the result of an 'Auto' by being able to intercept the @(b,
-- 'Auto' m a b)@ output and return a new output value @m c@.
--
-- Note that this is a lot like 'fmap':
--
-- @
-- fmap :: (b -> c) -> Auto m a b -> Auto m a c
-- @
--
  Except gives you access to both the @b@ and the " updated ' Auto ' " ;
  instead of an @b - > c@ , you get to pass a @(b , ' Auto ' m a b ) - > m c@.
--
-- Basically experimenting with a bunch of abstractions over different
-- lower-level modification of 'Auto's, because making sure the
-- serialization works as planned can be a bit difficult.
--
interceptO :: Monad m
           => ((b, Auto m a b) -> m c)      -- ^ intercepting function
           -> Auto m a b
           -> Auto m a c
interceptO f = go
  where
    go a0 = mkAutoM (go <$> resumeAuto a0)
                    (saveAuto a0)
                  $ \x -> do
                        o@(_, a1) <- stepAuto a0 x
                        y <- f o
                        return (y, go a1)

  compMAuto : : (   , Monad m ' ) = > Auto m b ( m ' c ) - > Auto m a ( m ' b ) - > Auto m a ( m ' c )
-- compMAuto g f = AutoArbM undefined
--                          undefined
                           $ \x - > do
--                              Output y f' <- stepAuto f x
--                              undefined


-- doesn't work like you'd think lol.
  serialForcer : :   = > Auto m a a
-- serialForcer = a
--   where
      a = mkAuto _ $ \x - > let outp = Output x a
--                         in  forceSerial a `seq` outp

-- | Construct an 'Auto' by explicity giving its serialization,
-- deserialization, and the function from @a@ to a @b@ and "updated
-- 'Auto'".
--
-- Ideally, you wouldn't have to use this unless you are making your own
-- framework.  Try your best to make what you want by assembling
  primtives together .   Working with serilization directly is hard .
--
-- See 'mkAutoM' for more detailed instructions on doing this right.
mkAuto :: Get (Auto m a b)          -- ^ resuming/loading 'Get'
       -> Put                       -- ^ saving 'Put'
       -> (a -> (b, Auto m a b))    -- ^ step function
       -> Auto m a b
mkAuto = AutoArb
# INLINE mkAuto #

-- | Construct an 'Auto' by explicitly giving its serializiation,
-- deserialization, and the (monadic) function from @a@ to a @b@ and the
-- "updated 'Auto'".
--
-- See the "serialization" section in the "Control.Auto.Core" module for
-- more information.
--
-- Ideally, you wouldn't have to use this unless you are making your own
-- framework.  Try your best to make what you want by assembling
  primtives together .
--
-- But sometimes you have to write your own combinators, and you're going
-- to have to use 'mkAutoM' to make it work.
--
-- Sometimes, it's simple:
--
-- @
-- fmap :: (a -> b) -> Auto r a -> Auto r b
-- fmap f a0 = mkAutoM (do aResumed <- resumeAuto a0
                          return ( fmap f aResumed )   )
--                     (saveAuto a0)
                      $ \x - > do
--                         (y, a1) <- stepAuto a0 x
--                         return (f y, fmap f a1)
-- @
--
  Serializing @'fmap ' f a0@ is just the same as serializing @a0@.   And to
  resume it , we resume @a0@ to get a resumed version of @a0@ , and then we
  apply @'fmap ' f@ to the ' Auto ' that we resumed .
--
-- Also another nice "simple" example is:
--
-- @
-- catchA :: Exception e
--        => Auto IO a b
--        -> Auto IO a (Either e b)
-- catchA a = mkAutoM (do aResumed <- resumeAuto a
--                        return (catchA aResumed) )
--                    (saveAuto a)
                   $ \x - > do
--                      eya' <- try $ stepAuto a x
--                      case eya' of
--                        Right (y, a') -> return (Right y, catchA a')
--                        Left e        -> return (Left e , catchA a )
-- @
--
-- Which is basically the same principle, in terms of serializing and
-- resuming strategies.
--
-- When you have "switching" --- things that behave like different 'Auto's
-- at different points in time --- then things get a little complicated,
-- because you have to figure out which 'Auto' to resume.
--
-- For example, let's look at the source of '-?>':
--
-- @
  ( - ? > ) : :  
--       => Interval m a b   -- ^ initial behavior
--       -> Interval m a b   -- ^ final behavior, when the initial
--                           --   behavior turns off.
--       -> Interval m a b
-- a1 -?> a2 = mkAutoM l s t
--   where
--     l = do
--       flag <- get
--       if flag
--         then resumeAuto (switched a2)
--         else (-?> a2) <$> resumeAuto a1
--     s = put False *> saveAuto a1
--     t x = do
--       (y1, a1') <- stepAuto a1 x
--       case y1 of
--         Just _  ->
--           return (y1, a1' -?> a2)
--         Nothing -> do
--           (y, a2') <- stepAuto a2 x
--           return (y, switched a2')
--     switched a = mkAutoM l
--                          (put True  *> saveAuto a)
                         $ \x - > do
--                            (y, a') <- stepAuto a x
--                            return (y, switched a')
-- @
--
-- We have to invent a serialization and reloading scheme, taking into
  account the two states that the resulting ' Auto ' can be in :
--
  1 .    Initially , it is behaving like @a1@.   So , to save it , we put
       a flag saying that we are still in stage 1 ( ' False ' ) , and then
       put @a1@ 's current serialization data .
  2 .    After the switch , it is behaving like @a2@.   So , to save it , we put
       a flag saying that we are now in stage 2 ( ' True ' ) , and then put
--      @a2@'s current.
--
  Now , when we /resume/ @a1 ' - ? > ' a2@ , ' resumeAuto ' on @a1 ' - ? > ' a2@ will
-- give us @l@.  So the 'Get' we use --- the process we use to resume the
-- entire @a1 '-?>' a2@, will /start/ at the initial 'Get'/loading
-- function, @l@ here.  We have to encode our branching and
-- resuming/serialization scheme into the initial, front-facing @l@.  So
-- @l@ has to check for the flag, and if the flag is true, load in the data
-- for the switched state; otherwise, load in the data for the pre-switched
-- state.
--
-- Not all of them are this tricky.  Mostly "switching" combinators will be
-- tricky, because switching means changing what you are serializing.
--
-- This one might be considerably easier, because of 'mapM':
--
-- @
  zipAuto : :  
--         => a                -- ^ default input value
--         -> [Auto m a b]     -- ^ 'Auto's to zip up
--         -> Auto m [a] [b]
-- zipAuto x0 as = mkAutoM (zipAuto x0 <$> mapM resumeAuto as)
--                         (mapM_ saveAuto as)
--                         $ \xs -> do
                                        repeat  )
--                             let (ys, as') = unzip res
                              return ( ys ,   as ' )
-- @
--
-- To serialize, we basically sequence 'saveAuto' over all of the internal
  ' Auto 's --- serialize each of their serialization data one - by - one one
-- after the other in our binary.
--
-- To load, we do the same thing; we go over every 'Auto' in @as@ and
-- 'resumeAuto' it, and then collect the results in a list --- a list of
-- resumed 'Auto's.  And then we apply @'zipAuto' x0@ to that list of
  ' Auto 's , to get our resumed @'zipAuto '  as@.
--
-- So, it might be complicated.  In the end, it might be all worth it, too,
-- to have implicit serialization compose like this.  Think about your
  serialization strategy first .   Step back and think about what you need
-- to serialize at every step, and remember that it's _the initial_
-- "resuming" function that has to "resume everything"...it's not the
-- resuming function that exists when you finally save your 'Auto', it's
-- the resuming 'Get' that was there /at the beginning/.  For '-?>', the
  intial @l@ had to know how to " skip ahead " .
--
-- And of course as always, test.
--
-- If you need to make your own combinator or transformer but are having
-- trouble with the serializtion, feel free to contact me at
-- <>, on freenode at /#haskell/ or /#haskell-auto/, open
-- a < github issue>, etc.  Just
-- contact me somehow, I'll be happy to help!
--
mkAutoM :: Get (Auto m a b)             -- ^ resuming/loading 'Get'
        -> Put                          -- ^ saving 'Put'
        -> (a -> m (b, Auto m a b))     -- ^ (monadic) step function
        -> Auto m a b
mkAutoM = AutoArbM
# INLINE mkAutoM #

-- | Like 'mkAuto', but without any way of meaningful serializing or
-- deserializing.
--
-- Be careful!  This 'Auto' can still carry arbitrary internal state, but
-- it cannot be meaningfully serialized or re-loaded/resumed.  You can
-- still pretend to do so using
-- 'resumeAuto'/'saveAuto'/'encodeAuto'/'decodeAuto' (and the type system
-- won't stop you), but when you try to "resume"/decode it, its state will
-- be lost.
mkAuto_ :: (a -> (b, Auto m a b))       -- ^ step function
        -> Auto m a b
mkAuto_ f = mkAuto (pure (mkAuto_ f)) (return ()) f
{-# INLINE mkAuto_ #-}

-- | Like 'mkAutoM', but without any way of meaningful serializing or
-- deserializing.
--
-- Be careful!  This 'Auto' can still carry arbitrary internal state, but
-- it cannot be meaningfully serialized or re-loaded/resumed.  You can
-- still pretend to do so using
-- 'resumeAuto'/'saveAuto'/'encodeAuto'/'decodeAuto' (and the type system
-- won't stop you), but when you try to "resume"/decode it, its state will
-- be reset.
mkAutoM_ :: (a -> m (b, Auto m a b))    -- ^ (monadic) step function
         -> Auto m a b
mkAutoM_ f = mkAutoM (pure (mkAutoM_ f)) (return ()) f
{-# INLINE mkAutoM_ #-}

-- | Construct the 'Auto' whose output is always the given value, ignoring
-- its input.
--
-- Provided for API constency, but you should really be using 'pure' from
-- the 'Applicative' instance, from "Control.Applicative", which does the
-- same thing.
mkConst :: b            -- ^ constant value to be outputted
        -> Auto m a b
mkConst = AutoFunc . const
# INLINE mkConst #

-- | Construct the 'Auto' that always "executes" the given monadic value at
-- every step, yielding the result as its output and ignoring its input.
--
-- Provided for API consistency, but you shold really be using 'effect'
-- from "Control.Auto.Effects", which does the same thing.
mkConstM :: m b           -- ^ monadic action to be executed at every step
         -> Auto m a b
mkConstM = AutoFuncM . const
# INLINE mkConstM #

-- | Construct a stateless 'Auto' that simply applies the given (pure)
-- function to every input, yielding the output.  The output stream is just
-- the result of applying the function to every input.
--
-- prop> streamAuto' (mkFunc f) = map f
--
  This is rarely needed ; you should be using ' arr ' from the ' Arrow '
-- instance, from "Control.Arrow".
mkFunc :: (a -> b)        -- ^ pure function
       -> Auto m a b
mkFunc = AutoFunc
# INLINE mkFunc #

-- | Construct a stateless 'Auto' that simply applies and executes the givne
-- (monadic) function to every input, yielding the output.  The output
-- stream is the result of applying the function to every input,
-- executing/sequencing the action, and returning the returned value.
--
-- prop> streamAuto (mkFuncM f) = mapM f
--
-- It's recommended that you use 'arrM' from "Control.Auto.Effects".  This
-- is only really provided for consistency.
mkFuncM :: (a -> m b)     -- ^ "monadic" function
        -> Auto m a b
mkFuncM = AutoFuncM
# INLINE mkFuncM #

  | Construct an ' Auto ' from a state transformer : an @a - > s - > ( b , s)@
-- gives you an @'Auto' m a b@, for any 'Monad' @m@.  At every step, it
-- takes in the @a@ input, runs the function with the stored internal
  state , returns the @b@ result , and now contains the new resulting state .
-- You have to intialize it with an initial state, of course.
--
-- From the "stream transformer" point of view, this is rougly equivalent
-- to 'mapAccumL' from "Data.List", with the function's arguments and
-- results in the backwards order.
--
  prop > streamAuto ' ( mkState f s0 ) = snd .  (     swap ( f x s ) )
--
-- Try not to use this if it's ever avoidable, unless you're a framework
-- developer or something.  Try make something by combining/composing the
-- various 'Auto' combinators.
--
  If your state @s@ does not have a ' Serialize ' instance , then you should
-- either write a meaningful one, provide the serialization methods
-- manually with 'mkState'', or throw away serializability and use
-- 'mkState_'.
mkState :: Serialize s
        => (a -> s -> (b, s))       -- ^ state transformer
        -> s                        -- ^ intial state
        -> Auto m a b
mkState = AutoState (get, put)
# INLINE mkState #

  | Construct an ' Auto ' from a " monadic " state transformer : @a - > s - >
  m ( b , s)@ gives you an @'Auto ' m a b@.   At every step , it takes in the
-- @a@ input, runs the function with the stored internal state and
  " executes " the @m ( b , s)@ to get the @b@ output , and stores the @s@ as
-- the new, updated state.  Must be initialized with an initial state.
--
-- Try not to use this if it's ever avoidable, unless you're a framework
-- developer or something.  Try make something by combining/composing the
-- various 'Auto' combinators.
--
-- This version is a wrapper around 'mkAuto', that keeps track of the
-- serialization and re-loading of the internal state for you, so you don't
-- have to deal with it explicitly.
--
  If your state @s@ does not have a ' Serialize ' instance , then you should
-- either write a meaningful one, provide the serialization methods
-- manually with 'mkStateM'', or throw away serializability and use
-- 'mkStateM_'.
mkStateM :: Serialize s
         => (a -> s -> m (b, s))      -- ^ (monadic) state transformer
         -> s                         -- ^ initial state
         -> Auto m a b
mkStateM = AutoStateM (get, put)
# INLINE mkStateM #

  | A version of ' mkState ' , where the internal state does n't have
  a ' Serialize ' instance , so you provide your own instructions for getting
-- and putting the state.
--
-- See 'mkState' for more details.
mkState' :: Get s                     -- ^ 'Get'; strategy for reading and deserializing the state
         -> (s -> Put)                -- ^ 'Put'; strategy for serializing given state
         -> (a -> s -> (b, s))        -- ^ state transformer
         -> s                         -- ^ intial state
         -> Auto m a b
mkState' = curry AutoState
# INLINE mkState ' #

-- | A version of 'mkStateM', where the internal state doesn't have
  a ' Serialize ' instance , so you provide your own instructions for getting
-- and putting the state.
--
-- See 'mkStateM' for more details.
mkStateM' :: Get s                      -- ^ 'Get'; strategy for reading and deserializing the state
          -> (s -> Put)                 -- ^ 'Put'; strategy for serializing given state
          -> (a -> s -> m (b, s))       -- ^ (monadic) state transformer
          -> s                          -- ^ initial state
          -> Auto m a b
mkStateM' = curry AutoStateM
# INLINE mkStateM ' #

  | A version of ' mkState ' , where the internal state is n't serialized .   It
-- can be "saved" and "loaded", but the state is lost in the process.
--
-- See 'mkState' for more details.
--
  Useful if your state @s@ can not have a meaningful ' Serialize ' instance .
mkState_ :: (a -> s -> (b, s))    -- ^ state transformer
         -> s                     -- ^ initial state
         -> Auto m a b
mkState_ f s0 = AutoState (return s0, \_ -> return ()) f s0
{-# INLINE mkState_ #-}

-- | A version of 'mkStateM', where the internal state isn't serialized.
-- It can be "saved" and "loaded", but the state is lost in the process.
--
-- See 'mkStateM' for more details.
--
  Useful if your state @s@ can not have a meaningful ' Serialize ' instance .
mkStateM_ :: (a -> s -> m (b, s))   -- ^ (monadic) state transformer
          -> s                      -- ^ initial state
          -> Auto m a b
mkStateM_ f s0 = AutoStateM (return s0, \_ -> return ()) f s0
# INLINE mkStateM _ #

-- | Construct an 'Auto' from a "folding" function: @b -> a -> b@ yields an
  @'Auto ' m a b@.   Basically acts like a ' foldl ' or a '  ' .   There is
-- an internal accumulator that is "updated" with an @a@ at every step.
-- Must be given an initial accumulator.
--
-- Example: an 'Auto' that sums up all of its input.
--
  > > > let summer =  ( + ) 0
  > > > let (  , summer ' )   = stepAuto ' summer 3
  > > > 
  3
  > > > let ( sum2 , summer '' ) = stepAuto ' summer ' 10
-- >>> sum2
  13
  > > > streamAuto '   summer '' [ 1 .. 10 ]
  [  ]
--
  If your accumulator  does not have a ' Serialize ' instance , then you
-- should either write a meaningful one, or throw away serializability and
-- use 'accum_'.
accum :: Serialize b
      => (b -> a -> b)      -- ^ accumulating function
      -> b                  -- ^ initial accumulator
      -> Auto m a b
accum f = mkState (\x s -> let y = f s x in (y, y))
# INLINE accum #

-- | Construct an 'Auto' from a "monadic" "folding" function: @b -> a ->
  m b@ yields an @'Auto ' m a b@.   Basically acts like a ' foldM ' or ' scanM '
-- (if it existed).  here is an internal accumulator that is "updated" with
-- an input @a@ with the result of the executed @m b@ at every step.  Must
-- be given an initial accumulator.
--
-- See 'accum' for more details.
--
  If your accumulator  does not have a ' Serialize ' instance , then you
-- should either write a meaningful one, or throw away serializability and
-- use 'accumM_'.
accumM :: (Serialize b, Monad m)
       => (b -> a -> m b)       -- ^ (monadic) accumulating function
       -> b                     -- ^ initial accumulator
       -> Auto m a b
accumM f = mkStateM (\x s -> liftM (join (,)) (f s x))
# INLINE accumM #

-- | A version of 'accum', where the internal accumulator isn't
-- serialized. It can be "saved" and "loaded", but the state is lost in the
-- process.
--
-- See 'accum' for more details.
--
  Useful if your accumulator  can not have a meaningful ' Serialize '
-- instance.
accum_ :: (b -> a -> b)   -- ^ accumulating function
         -> b               -- ^ intial accumulator
         -> Auto m a b
accum_ f = mkState_ (\x s -> let y = f s x in (y, y))
# INLINE accum _ #

-- | A version of 'accumM_, where the internal accumulator isn't
-- serialized. It can be "saved" and "loaded", but the state is lost in the
-- process.
--
-- See 'accumM' for more details.
--
  Useful if your accumulator  can not have a meaningful ' Serialize '
-- instance.
accumM_ :: Monad m
          => (b -> a -> m b)    -- ^ (monadic) accumulating function
          -> b                  -- ^ initial accumulator
          -> Auto m a b
accumM_ f = mkStateM_ (\x s -> liftM (join (,)) (f s x))
{-# INLINE accumM_ #-}

  | A " delayed " version of ' accum ' , where the first output is the initial
-- state of the accumulator, before applying the folding function. Useful
-- in recursive bindings.
--
  > > > let summerD = accumD ( + ) 0
  > > > let (  , summerD ' )   = stepAuto ' summerD 3
  > > > 
  0
  > > > let ( sum2 , summerD '' ) = stepAuto ' summerD ' 10
-- >>> sum2
  3
  > > > streamAuto '   summerD '' [ 1 .. 10 ]
-- [13,14,16,19,23,28,34,41,49,58]
--
-- (Compare with the example in 'accum')
--
  Note that this is more or less an encoding of '  ' , that can be
-- "decoded" with 'streamAuto'':
--
-- >>> let myScanl f z = streamAuto' (accumD f z)
  > > >  ( + ) 0 [ 1 .. 10 ]
-- [0,3,6,10,15,21,28,36,45,55]
  > > > myScanl ( + ) 0 [ 1 .. 10 ]
-- [0,3,6,10,15,21,28,36,45]
--
-- The only difference is that you don't get the last element.  (You could
-- force it out, if you wanted, by feeding any nonsense value in --- even
-- 'undefined'! --- and getting the result)
--
accumD :: Serialize b
         => (b -> a -> b)      -- ^ accumulating function
         -> b                  -- ^ initial accumulator
         -> Auto m a b
accumD f = mkState (\x s -> (s, f s x))
# INLINE accumD #

  | A " delayed " version of ' accumM ' , where the first output is the initial
-- state of the accumulator, before applying the folding function. Useful
-- in recursive bindings.
accumMD :: (Serialize b, Monad m)
          => (b -> a -> m b)       -- ^ (monadic) accumulating function
          -> b                     -- ^ initial accumulator
          -> Auto m a b
accumMD f = mkStateM (\x s -> liftM (s,) (f s x))
# INLINE accumMD #

-- | The non-resuming/non-serializing version of 'accumD'.
accumD_ :: (b -> a -> b)   -- ^ accumulating function
          -> b               -- ^ intial accumulator
          -> Auto m a b
accumD_ f = mkState_ (\x s -> (s, f s x))
{-# INLINE accumD_ #-}

-- | The non-resuming/non-serializing version of 'accumMD'.
accumMD_ :: Monad m
           => (b -> a -> m b)    -- ^ (monadic) accumulating function
           -> b                  -- ^ initial accumulator
           -> Auto m a b
accumMD_ f = mkStateM_ (\x s -> liftM (s,) (f s x))
# INLINE accumMD _ #

-- | Maps over the output stream of the 'Auto'.
--
  > > > streamAuto ' ( sumFrom 0 ) [ 1 .. 10 ]
  [ 1,3,6,10,15,21,28,36,45,55 ]
  > > > streamAuto ' ( show < $ > sumFrom 0 ) [ 1 .. 10 ]
  [ " 1","3","6","10","15","21","28","36","45","55 " ]
instance Monad m => Functor (Auto m a) where
    fmap = rmap
# INLINE fmap #

-- | 'pure' creates the "constant" 'Auto':
--
  > > > streamAuto ' ( pure " foo " ) [ 1 .. 5 ]
-- ["foo","foo","foo","foo","foo"]
--
-- '<*>' and 'liftA2' etc. give you the ability to fork the input stream
-- over many 'Auto's, and recombine the results:
--
  > > > streamAuto ' ( sumFrom 0 ) [ 1 .. 10 ]
  [ 1 , 3 ,   6 , 10 ,   15 ]
  > > > streamAuto ' ( productFrom 1 ) [ 1 .. 10 ]
  [ 1 , 2 ,   6 , 24 , 120 ]
  > > > streamAuto ' ( liftA2 ( + ) ( sumFrom 0 ) ( productFrom 1 ) ) [ 1 .. 5 ]
  [ 2 , 5 , 12 , 34 , 135 ]
--
-- For effectful 'Auto', you can imagine '*>' as "forking" the input stream
  through both , and only keeping the result of the second :
--
-- @
-- 'effect' 'print' *> 'sumFrom' 0
-- @
--
  would , for example , behave just like @'sumFrom ' 0@ , except printing the
-- input to 'IO' at every step.
--
instance Monad m => Applicative (Auto m a) where
    pure      = mkConst
# INLINE pure #
    af <*> ax = case (af, ax) of
                  (AutoFunc f, AutoFunc x)  ->
                      AutoFunc (f <*> x)
                  (AutoFunc f, AutoFuncM x) ->
                      AutoFuncM $ \i -> liftM (f i) (x i)
                  (AutoFunc f, AutoState gp x s) ->
                      AutoState gp (\i s' -> first (f i) (x i s')) s
                  (AutoFunc f, AutoStateM gp x s) ->
                      AutoStateM gp (\i s' -> liftM (first (f i)) (x i s')) s
                  (AutoFunc f, AutoArb l s x) ->
                      AutoArb (fmap (af <*>) l) s $ \i -> (f i *** (af <*>)) $ x i
                  (AutoFunc f, AutoArbM l s x) ->
                      AutoArbM (fmap (af <*>) l) s $ \i -> liftM (f i *** (af <*>)) (x i)
                  (AutoFuncM f, AutoFunc x) ->
                      AutoFuncM $ \i -> liftM ($ x i) (f i)
                  (AutoFuncM f, AutoFuncM x) ->
                      AutoFuncM $ \i -> f i `ap` x i
                  (AutoFuncM f, AutoState gp x s) ->
                      AutoStateM gp (\i s' -> liftM (($ x i s') . first) (f i)) s
                  (AutoFuncM f, AutoStateM gp x s) ->
                      AutoStateM gp (\i s' -> liftM2 first (f i) (x i s')) s
                  (AutoFuncM f, AutoArb l s x) ->
                      AutoArbM (fmap (af <*>) l) s $ \i -> liftM (($ x i) . (*** (af <*>))) (f i)
                  (AutoFuncM f, AutoArbM l s x) ->
                      AutoArbM (fmap (af <*>) l) s $ \i -> liftM2 (*** (af <*>)) (f i) (x i)
                  (AutoState gp f s, AutoFunc x) ->
                      AutoState gp (\i s' -> first ($ x i) (f i s')) s
                  (AutoState gp f s, AutoFuncM x) ->
                      AutoStateM gp (\i s' -> liftM (\x' -> first ($ x') (f i s')) (x i)) s
                  (AutoState gpf f sf, AutoState gpx x sx) ->
                      AutoState (mergeStSt gpf gpx)
                                (\i (sf', sx') -> let (f', sf'') = f i sf'
                                                      (x', sx'') = x i sx'
                                                  in  (f' x', (sf'', sx'')))
                                (sf, sx)
                  (AutoState gpf f sf, AutoStateM gpx x sx) ->
                      AutoStateM (mergeStSt gpf gpx)
                                 (\i (sf', sx') -> do let (f', sf'') = f i sf'
                                                      (x', sx'') <- x i sx'
                                                      return (f' x', (sf'', sx'')))
                                 (sf, sx)
                  (AutoStateM gp f s, AutoFunc x) ->
                      AutoStateM gp (\i s' -> liftM (first ($ x i)) (f i s')) s
                  (AutoStateM gp f s, AutoFuncM x) ->
                      AutoStateM gp (\i s' -> do (f', s'') <- f i s'
                                                 x' <- x i
                                                 return (f' x', s'')
                                    ) s
                  (AutoStateM gpf f sf, AutoState gpx x sx) ->
                      AutoStateM (mergeStSt gpf gpx)
                                 (\i (sf', sx') -> do (f', sf'') <- f i sf'
                                                      let (x', sx'') = x i sx'
                                                      return (f' x', (sf'', sx''))
                                 ) (sf, sx)
                  (AutoStateM gpf f sf, AutoStateM gpx x sx) ->
                      AutoStateM (mergeStSt gpf gpx)
                                 (\i (sf', sx') -> do (f', sf'') <- f i sf'
                                                      (x', sx'') <- x i sx'
                                                      return (f' x', (sf'', sx''))
                                 ) (sf, sx)
                  -- i give up!
                  _ -> uncurry ($) <$> (af &&& ax)
    {-# INLINE (<*>) #-}

  | When the underlying ' Monad'/'Applicative ' @m@ is an ' Alternative ' ,
-- fork the input through each one and "squish" their results together
-- inside the 'Alternative' context.  See 'runTraversableA' for similar use
-- cases.
--
  > > > streamAuto ( arrM ( mfilter even . Just ) ) [ 1 .. 10 ]
-- Nothing
  > > > streamAuto ( arrM ( Just . negate ) ) [ 1 .. 10 ]
-- Just [-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
  > > > streamAuto ( arrM ( mfilter even . Just ) ) < | > arrM ( Just . negate ) ) [ 1 .. 10 ]
-- Just [-1,2,-3,4,-5,6,-7,8,-9,10]
--
instance (Monad m, Alternative m) => Alternative (Auto m a) where
    empty     = mkConstM empty
    a1 <|> a2 = mkAutoM ((<|>) <$> resumeAuto a1 <*> resumeAuto a2)
                        (saveAuto a1 *> saveAuto a2)
                        $ \x -> let res1  = second (<|> a2) `liftM` stepAuto a1 x
                                    res2  = second (a1 <|>) `liftM` stepAuto a2 x
                                in  res1 <|> res2

-- | Gives the ability to "compose" two 'Auto's; feeds the input stream
  into the first , feeds that output stream into the second , and returns as
  a result the output stream of the second .
instance Monad m => Category (Auto m) where
    id      = mkFunc id
    ag . af = case (ag, af) of
                (AutoFunc g, AutoFunc f)          ->
                    AutoFunc   (g . f)
                (AutoFunc g, AutoFuncM f)         ->
                    AutoFuncM  (return . g <=< f)
                (AutoFunc g, AutoState gpf f s)   ->
                    AutoState gpf (\x s' -> first g (f x s')) s
                (AutoFunc g, AutoStateM gpf f s)  ->
                    AutoStateM gpf (\x s' -> liftM (first g) (f x s')) s
                (AutoFunc g, AutoArb l s f)       ->
                    AutoArb (fmap (ag .) l) s $ \x -> (g *** fmap g) (f x)
                (AutoFunc g, AutoArbM l s f)      ->
                    AutoArbM (fmap (ag .) l) s $ \x -> liftM (g *** fmap g) (f x)
                (AutoFuncM g, AutoFunc f)         ->
                    AutoFuncM (g <=< return . f)
                (AutoFuncM g, AutoFuncM f)        ->
                    AutoFuncM (g <=< f)
                (AutoFuncM g, AutoState gpf f s)  ->
                    AutoStateM gpf (\x s' -> firstM g (f x s')) s
                (AutoFuncM g, AutoStateM gpf f s) ->
                    AutoStateM gpf (\x s' -> firstM g =<< f x s') s
                (AutoFuncM g, AutoArb l s f)      ->
                    AutoArbM (fmap (ag .) l)
                             s
                           $ \x -> do
                               let (y, af') = f x
                               y' <- g y
                               return (y', ag . af')
                (AutoFuncM g, AutoArbM l s f)     ->
                    AutoArbM (fmap (ag .) l)
                             s
                           $ \x -> do
                               (y, af') <- f x
                               y' <- g y
                               return (y', ag . af')
                (AutoState gpg g sg, AutoFunc f)  ->
                    AutoState gpg (g . f) sg
                (AutoState gpg g sg, AutoFuncM f) ->
                    AutoStateM gpg (\x sg' -> liftM (`g` sg') (f x)) sg
                (AutoState gpg g sg, AutoState gpf f sf) ->
                    AutoState (mergeStSt gpg gpf)
                              (\x (sg', sf') -> let (y, sf'') = f x sf'
                                                    (z, sg'') = g y sg'
                                                in  (z, (sg'', sf'')) )
                              (sg, sf)
                (AutoState gpg g sg, AutoStateM gpf f sf) ->
                    AutoStateM (mergeStSt gpg gpf)
                               (\x (sg', sf') -> do
                                    (y, sf'') <- f x sf'
                                    let (z, sg'') = g y sg'
                                    return (z, (sg'', sf'')) )
                               (sg, sf)
                (AutoState gpg@(gg,pg) g sg, AutoArb l s f) ->
                    AutoArb (liftA2 (\sg' af' -> AutoState gpg g sg' . af') gg l)
                            (pg sg *> s)
                            $ \x -> let (y, af') = f x
                                        (z, sg') = g y sg
                                        ag'      = AutoState gpg g sg'
                                    in  (z, ag' . af')
                (AutoState gpg@(gg,pg) g sg, AutoArbM l s f) ->
                    AutoArbM (liftA2 (\sg' af' -> AutoState gpg g sg' . af') gg l)
                             (pg sg *> s)
                             $ \x -> do
                                 (y, af') <- f x
                                 let (z, sg') = g y sg
                                     ag'      = AutoState gpg g sg'
                                 return (z, ag' . af')
                (AutoStateM gpg g sg, AutoFunc f)       ->
                    AutoStateM gpg (g <=< return . f) sg
                (AutoStateM gpg g sg, AutoFuncM f)      ->
                    AutoStateM gpg (\x sg' -> flip g sg' =<< f x) sg
                (AutoStateM gpg g sg, AutoState gpf f sf) ->
                    AutoStateM (mergeStSt gpg gpf)
                               (\x (sg', sf') -> do
                                  let (y, sf'') = f x sf'
                                  (z, sg'') <- g y sg'
                                  return (z, (sg'', sf'')) )
                               (sg, sf)
                (AutoStateM gpg g sg, AutoStateM gpf f sf) ->
                    AutoStateM (mergeStSt gpg gpf)
                               (\x (sg', sf') -> do
                                  (y, sf'') <- f x sf'
                                  (z, sg'') <- g y sg'
                                  return (z, (sg'', sf'')) )
                               (sg, sf)
                (AutoStateM gpg@(gg,pg) g sg, AutoArb l s f) ->
                    AutoArbM (liftA2 (\sg' af' -> AutoStateM gpg g sg' . af') gg l)
                             (pg sg *> s)
                             $ \x -> do
                                 let (y, af') = f x
                                 (z, sg') <- g y sg
                                 let ag' = AutoStateM gpg g sg'
                                 return (z, ag' . af')
                (AutoStateM gpg@(gg,pg) g sg, AutoArbM l s f) ->
                    AutoArbM (liftA2 (\sg' af' -> AutoStateM gpg g sg' . af') gg l)
                             (pg sg *> s)
                             $ \x -> do
                                 (y, af') <- f x
                                 (z, sg') <- g y sg
                                 let ag' = AutoStateM gpg g sg'
                                 return (z, ag' . af')
                (AutoArb l s g, AutoFunc f)  ->
                    AutoArb (fmap (. af) l) s (second (. af) . g . f)
                (AutoArb l s g, AutoFuncM f) ->
                    AutoArbM (fmap (. af) l) s (return . second (. af) . g <=< f)
                (AutoArb l s g, AutoState gpf@(gf,pf) f sf) ->
                    AutoArb (liftA2 (\ag' sf' -> ag' . AutoState gpf f sf') l gf)
                            (s *> pf sf)
                            $ \x -> let (y, sf') = f x sf
                                        af'      = AutoState gpf f sf'
                                        (z, ag') = g y
                                    in  (z, ag' . af')
                (AutoArb l s g, AutoStateM gpf@(gf,pf) f sf) ->
                    AutoArbM (liftA2 (\ag' sf' -> ag' . AutoStateM gpf f sf') l gf)
                             (s *> pf sf)
                             $ \x -> do
                                 (y, sf') <- f x sf
                                 let af'      = AutoStateM gpf f sf'
                                     (z, ag') = g y
                                 return (z, ag' . af')
                (AutoArb lg sg g, AutoArb lf sf f) ->
                    AutoArb (liftA2 (.) lg lf)
                            (sg *> sf)
                            $ \x -> let (y, af') = f x
                                        (z, ag') = g y
                                    in  (z, ag' . af')
                (AutoArb lg sg g, AutoArbM lf sf f) ->
                    AutoArbM (liftA2 (.) lg lf)
                             (sg *> sf)
                             $ \x -> do
                                 (y, af') <- f x
                                 let (z, ag') = g y
                                 return (z, ag' . af')
                (AutoArbM l s g, AutoFunc f)  ->
                    AutoArbM (fmap (. af) l)
                             s
                             (liftM (second (. af)) . g . f)
                (AutoArbM l s g, AutoFuncM f) ->
                    AutoArbM (fmap (. af) l)
                             s
                             (liftM (second (. af)) . g <=< f)
                (AutoArbM l s g, AutoState gpf@(gf,pf) f sf) ->
                    AutoArbM (liftA2 (\ag' sf' -> ag' . AutoState gpf f sf') l gf)
                             (s *> pf sf)
                             $ \x -> do
                                 let (y, sf') = f x sf
                                     af'      = AutoState gpf f sf'
                                 (z, ag') <- g y
                                 return (z, ag' . af')
                (AutoArbM l s g, AutoStateM gpf@(gf,pf) f sf) ->
                    AutoArbM (liftA2 (\ag' sf' -> ag' . AutoStateM gpf f sf') l gf)
                             (s *> pf sf)
                             $ \x -> do
                                 (y, sf') <- f x sf
                                 let af' = AutoStateM gpf f sf'
                                 (z, ag') <- g y
                                 return (z, ag' . af')
                (AutoArbM lg sg g, AutoArb lf sf f) ->
                    AutoArbM (liftA2 (.) lg lf)
                             (sg *> sf)
                             $ \x -> do
                                 let (y, af') = f x
                                 (z, ag') <- g y
                                 return (z, ag' . af')
                (AutoArbM lg sg g, AutoArbM lf sf f) ->
                    AutoArbM (liftA2 (.) lg lf)
                             (sg *> sf)
                             $ \x -> do
                                 (y, af') <- f x
                                 (z, ag') <- g y
                                 return (z, ag' . af')
    {-# INLINE (.) #-}

mergeStSt :: (Get s, s -> Put)
          -> (Get s', s' -> Put)
          -> (Get (s, s'), (s, s') -> Put)
mergeStSt (gg, pg) (gf, pf) = (liftA2 (,) gg gf, uncurry (*>) . (pg *** pf))

-- | 'lmap' lets you map over the /input/ stream, and 'rmap' lets you map
  over the /output/ stream .   Note that , as with all ' Profunctor 's , ' rmap '
-- is 'fmap'.
instance Monad m => Profunctor (Auto m) where
    lmap f = a_
      where
        a_ a = case a of
                 AutoFunc fa         -> AutoFunc (fa . f)
                 AutoFuncM fa        -> AutoFuncM (fa . f)
                 AutoState gpg fa s  -> AutoState gpg (fa . f) s
                 AutoStateM gpg fa s -> AutoStateM gpg (fa . f) s
                 AutoArb l s fa      -> AutoArb (a_ <$> l)
                                                s
                                              $ \x -> let (y, a') = fa (f x)
                                                      in  (y, a_ a')
                 AutoArbM l s fa     -> AutoArbM (a_ <$> l)
                                                 s
                                              $ \x -> do
                                                  (y, a') <- fa (f x)
                                                  return (y, a_ a')
# INLINE lmap #
    rmap g = a_
      where
        a_ a = case a of
                 AutoFunc fa         -> AutoFunc (g . fa)
                 AutoFuncM fa        -> AutoFuncM (liftM g . fa)
                 AutoState gpg fa s  -> AutoState gpg (\x -> first g . fa x) s
                 AutoStateM gpg fa s -> AutoStateM gpg (\x -> liftM (first g) . fa x) s
                 AutoArb l s fa      -> AutoArb (a_ <$> l)
                                                s
                                              $ \x -> let (y, a') = fa x
                                                      in  (g y, a_ a')
                 AutoArbM l s fa     -> AutoArbM (a_ <$> l)
                                                 s
                                               $ \x -> do
                                                   (y, a') <- fa x
                                                   return (g y, a_ a')
# INLINE rmap #
    dimap f g = a_
      where
        a_ a = case a of
                 AutoFunc fa         -> AutoFunc (g . fa . f)
                 AutoFuncM fa        -> AutoFuncM (liftM g . fa . f)
                 AutoState gpg fa s  -> AutoState gpg (\x -> first g . fa (f x)) s
                 AutoStateM gpg fa s -> AutoStateM gpg (\x -> liftM (first g) . fa (f x)) s
                 AutoArb l s fa      -> AutoArb (a_ <$> l)
                                                s
                                              $ \x -> let (y, a') = fa (f x)
                                                      in  (g y, a_ a')
                 AutoArbM l s fa     -> AutoArbM (a_ <$> l)
                                                 s
                                               $ \x -> do
                                                   (y, a') <- fa (f x)
                                                   return (g y, a_ a')
# INLINE dimap #

-- | See 'Arrow' instance.
instance Monad m => Strong (Auto m) where
    first'  = first
    second' = second

  | See ' ArrowChoice ' instance
instance Monad m => Choice (Auto m) where
    left'  = left
    right' = right

  | See '  ' instance
instance MonadFix m => Costrong (Auto m) where
    unfirst = loop

-- | Gives us 'arr', which is a "stateless" 'Auto' that behaves just like
-- a function; its outputs are the function applied the corresponding
-- inputs.
--
  > > > streamAuto ' ( arr negate ) [ 1 .. 10 ]
-- [-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
--
  Also allows you to have an ' Auto ' run on only the " first " or " second "
-- field in an input stream that is tuples...and also allows 'Auto's to run
-- side-by-side on an input stream of tuples (run each on either tuple
-- field).
--
  > > > streamAuto ' ( sumFrom 0 ) [ 4,6,8,7 ]
  [ 4,10,18,25 ]
  > > > streamAuto ' ( first ( sumFrom 0 ) ) [ ( 4,True),(6,False),(8,False),(7,True ) ]
-- [(4,True),(10,False),(18,False),(25,True)]
  > > > streamAuto ' ( productFrom 1 ) [ 1,3,5,2 ]
-- [1,3,15,30]
  > > > streamAuto ' ( sumFrom 0 * * * productFrom 1 ) [ ( 4,1),(6,3),(8,5),(7,2 ) ]
-- [(4,1),(10,3),(18,15),(25,30)]
--
-- Most importantly, however, allows for "proc" notation; see the
-- < tutorial>!
-- for more details.
--
instance Monad m => Arrow (Auto m) where
    arr     = mkFunc
    first a = case a of
                AutoFunc f         ->
                    AutoFunc (first f)
                AutoFuncM f        ->
                    AutoFuncM (firstM f)
                AutoState gp fa s  ->
                    AutoState gp (\(x, z) -> first (,z) . fa x) s
                AutoStateM gp fa s ->
                    AutoStateM gp (\(x, z) -> liftM (first (,z)) . fa x) s
                AutoArb l s f      ->
                    AutoArb (first <$> l)
                            s
                          $ \(x, z) -> let (y, a') = f x
                                       in  ((y, z), first a')
                AutoArbM l s f     ->
                    AutoArbM (first <$> l)
                             s
                           $ \(x, z) -> do
                               (y, a') <- f x
                               return ((y, z), first a')
    second a = case a of
                 AutoFunc f         ->
                     AutoFunc (second f)
                 AutoFuncM f        ->
                     AutoFuncM (secondM f)
                 AutoState gp fa s  ->
                     AutoState gp (\(z, x) -> first (z,) . fa x) s
                 AutoStateM gp fa s ->
                     AutoStateM gp (\(z, x) -> liftM (first (z,)) . fa x) s
                 AutoArb l s f      ->
                     AutoArb (second <$> l)
                             s
                           $ \(z, x) -> let (y, a') = f x
                                        in  ((z, y), second a')
                 AutoArbM l s f     ->
                     AutoArbM (second <$> l)
                              s
                            $ \(z, x) -> do
                                (y, a') <- f x
                                return ((z, y), second a')

-- | Allows you to have an 'Auto' only act on "some" inputs (only on
-- 'Left's, for example), and be "paused" otherwise.
--
-- >>> streamAuto' (sumFrom 0) [1,4,2,5]
  [ 1,5,7,12 ]
  > > > streamAuto ' ( left ( sumFrom 0 ) ) [ Left 1 , Right ' a ' , Left 4 , Left 2 , Right ' b ' , Left 5 ]
  [ Left 1 , Right ' a ' , Left 5 , Left 6 , Right ' b ' , Left 12 ]
--
-- Again mostly useful for "proc" notation, with branching.
--
instance Monad m => ArrowChoice (Auto m) where
    left a0 = a
      where
        a = case a0 of
              AutoFunc f        ->
                  AutoFunc (left f)
              AutoFuncM f       ->
                  AutoFuncM (\x -> case x of
                               Right y -> return (Right y)
                               Left y  -> liftM Left (f y))
              AutoState gp f s  ->
                  AutoState gp (\x s' -> case x of
                                  Right y -> (Right y, s')
                                  Left y  -> first Left (f y s')
                               ) s
              AutoStateM gp f s ->
                  AutoStateM gp (\x s' -> case x of
                                   Right y -> return (Right y, s')
                                   Left y  -> liftM (first Left) (f y s')
                                ) s
              AutoArb l s f     ->
                  AutoArb (left <$> l)
                          s
                        $ \x -> case x of
                                  Right y -> (Right y, a)
                                  Left y  -> (Left *** left) (f y)
              AutoArbM l s f    ->
                  AutoArbM (left <$> l)
                           s
                         $ \x -> case x of
                                   Right y -> return (Right y, a)
                                   Left y  -> liftM (Left *** left) (f y)
    {-# INLINE left #-}
    right a0 = a
      where
        a = case a0 of
              AutoFunc f ->
                  AutoFunc (fmap f)
              AutoFuncM f ->
                  AutoFuncM (sequence . fmap f)
              AutoState gp f s  ->
                  AutoState gp (\x s' -> case x of
                                  Left y  -> (Left y, s')
                                  Right y -> first Right (f y s')
                               ) s
              AutoStateM gp f s ->
                  AutoStateM gp (\x s' -> case x of
                                   Left y  -> return (Left y, s')
                                   Right y -> liftM (first Right) (f y s')
                                ) s
              AutoArb l s f     ->
                  AutoArb (right <$> l)
                          s
                        $ \x -> case x of
                                  Left y  -> (Left y, a)
                                  Right y -> (Right *** right) (f y)
              AutoArbM l s f    ->
                  AutoArbM (right <$> l)
                           s
                         $ \x -> case x of
                                   Left y  -> return (Left y, a)
                                   Right y -> liftM (Right *** right) (f y)
# INLINE right #

-- | Finds the fixed point of self-referential 'Auto's (for example,
-- feeding the output stream of an 'Auto' to itself).  Mostly used with
-- proc notation to allow recursive bindings.
instance MonadFix m => ArrowLoop (Auto m) where
    loop a = case a of
                AutoFunc f        ->
                    AutoFunc (\x -> fst . fix $ \(_, d) -> f (x, d))
                AutoFuncM f       ->
                    AutoFuncM (\x -> liftM fst . mfix $ \(_, d) -> f (x, d))
                AutoState gp f s  ->
                    AutoState gp (\x s' -> first fst . fix $ \ ~((_, d), _) -> f (x, d) s') s
                AutoStateM gp f s ->
                    AutoStateM gp (\x s' -> liftM (first fst) . mfix $ \ ~((_, d), _) -> f (x, d) s') s
                AutoArb l s f     ->
                    AutoArb (loop <$> l)
                            s
                          $ \x -> (fst *** loop)
                                . fix
                                $ \ ~((_, d), _) -> f (x, d)
                AutoArbM l s f    ->
                    AutoArbM (loop <$> l)
                             s
                           $ \x -> liftM (fst *** loop)
                                 . mfix
                                 $ \ ~((_, d), _) -> f (x, d)
# INLINE loop #

-- Utility instances

-- | Fork the input stream and '<>' the outputs.  See the 'Monoid'
-- instance.
instance (Monad m, Semigroup b) => Semigroup (Auto m a b) where
    (<>) = liftA2 (<>)

  | Fork the input stream and mappend the outputs .   '  ' is a constant
  stream of '  's , ignoring its input .
--
  > > > streamAuto ' ( mconcat [ arr ( take 3 ) ,  ( + + ) " " ] ) [ " hello","world","good","bye " ]
-- ["helhello","worhelloworld","goohelloworldgood","byehelloworldgoodbye"]
instance (Monad m, Monoid b) => Monoid (Auto m a b) where
    mempty  = pure mempty
    mappend = liftA2 mappend

-- | String literals in code will be 'Auto's that constanty produce that
-- string.
--
  > > > take 6 . streamAuto ' ( onFor 2 . " hello " -- > " world " ) $ repeat ( )
-- ["hello","hello","world","world","world","world"]
instance (Monad m, IsString b) => IsString (Auto m a b) where
    fromString = pure . fromString

-- | Fork the input stream and add, multiply, etc. the outputs.  'negate'
-- will negate the ouptput stream.  'fromInteger' will be a constant stream
  of that ' Integer ' , so you can write ' Auto 's using numerical literals in
-- code:
--
  > > > streamAuto ' ( sumFrom 0 ) [ 1 .. 10 ]
  [ 1,3,6,10,15,21,28,36,45,55 ]
  > > > streamAuto ' ( 4 + sumFrom 0 ) [ 1 .. 10 ]
  [ 5,7,10,14,19,25,32,40,49,59 ]
--
instance (Monad m, Num b) => Num (Auto m a b) where
    (+)         = liftA2 (+)
    (*)         = liftA2 (*)
    (-)         = liftA2 (-)
    negate      = fmap negate
    abs         = fmap abs
    signum      = fmap signum
    fromInteger = pure . fromInteger

-- | Fork the input stream and divide the outputs.  'recip' maps 'recip' to
-- the output stream; 'fromRational' will be a constant stream of that
  ' Rational ' , so you can write ' Auto 's using numerical literals in code ;
  see '  ' instance .
instance (Monad m, Fractional b) => Fractional (Auto m a b) where
    (/)          = liftA2 (/)
    recip        = fmap recip
    fromRational = pure . fromRational

-- | A bunch of constant producers, mappers-of-output-streams, and
-- forks-and-recombiners.
instance (Monad m, Floating b) => Floating (Auto m a b) where
    pi      = pure pi
    exp     = fmap exp
    sqrt    = fmap sqrt
    log     = fmap log
    (**)    = liftA2 (**)
    logBase = liftA2 logBase
    sin     = fmap sin
    tan     = fmap tan
    cos     = fmap cos
    asin    = fmap asin
    atan    = fmap atan
    acos    = fmap acos
    sinh    = fmap sinh
    tanh    = fmap tanh
    cosh    = fmap cosh
    asinh   = fmap asinh
    atanh   = fmap atanh
    acosh   = fmap acosh

-- Utility functions

firstM :: Monad m => (a -> m b) -> (a, c) -> m (b, c)
firstM f ~(x, y) = liftM (, y) (f x)
# INLINE firstM #

secondM :: Monad m => (a -> m b) -> (c, a) -> m (c, b)
secondM f ~(x, y) = liftM (x,) (f y)
# INLINE secondM #

# LANGUAGE DeriveDataTypeable #
# LANGUAGE RankNTypes #
 |
 Module      : Control.Auto.Core
 Description : Core types, constructors, and utilities.
 Copyright   : (c) Justin Le 2015
 Stability   : unstable
 Portability : portable

 This module defines and provides the core types, (smart) constructors,
 and general high and low-level utilities used by the /auto/ library.

 Note that importing and using functions from this module in part voids
 some of the "semantic contracts" of the 'Auto' types you get, so use
 with caution!

 A lot of low-level functionality is provided here which is most likely
 unnecessary for most applications; many are mostly for internal usage or
 advanced/fine-grained usage.  It also isn't really enough to do too many
 useful things, either.  It's recommended that you import "Control.Auto"
 instead, which re-organizes the more useful parts of this module in
 addition with useful parts of others to provide a nice packaged entry
 point.  If something in here becomes useful for more than just
 fine-tuning or low-level tweaking, it is probably supposed to be in
 "Control.Auto" anyway.

 Information on how to use these types is available in the
 < tutorial>!

 * Auto
 ** Type
 ** Running
 $serializing
 ** Underlying monad
 ** Special modifiers
 * Auto constructors
 ** Lifting values and functions
 ** from Accumulators
 *** Result-first
 *** Initial accumulator-first
 ** Arbitrary Autos
 * Strictness
 | The 'Auto' type.  For this library, an 'Auto' semantically
 output that is preserved over multiple steps, where that relationship is
 (optionally) maintained within the context of a monad.

 A lot of fancy words, I know...but you can think of an 'Auto' as nothing
 more than a "stream transformer" of value streams.  A stream of
 sequential input values come in one at a time, and a stream of outputs
 pop out one at a time, as well.

 Using the 'streamAuto' function, you can "unwrap" the inner value stream
 a time, and I'll give you a list of @b@s, matching a relationship to

 @
 -- unwrap your inner [a] -> m [b]!
 @

 You can also turn an @'Auto' m a b@ into an /effects stream/ that
 executes effects sequentially with 'toEffectStream' and
 'streamAutoEffects', so you can run it with a ListT-compatible library
 like /pipes/.

 There's a handy type synonym 'Auto'' for relationships that don't really
 need a monadic context; the @m@ is just 'Identity':

 @
 @


 @
 -- unwrap your inner [a] -> [b]!
 'streamAuto'' :: 'Auto'' a b -> ([a] -> [b])
 @

 All of the 'Auto's given in this library maintain some sort of semantic
 relationship between streams --- for some, the outputs might be the
 inputs with a function applied; for others, the outputs might be the
 cumulative sum of the inputs.

 See the
 < tutorial>
 for more information!

 Operationally, an  @'Auto' m a b@ is implemented as a "stateful
 function".  A function from an @a@ where, every time you "apply" it, you

 You can get this function using 'stepAuto':

 @
 'stepAuto' :: 'Auto' m a b -> (a -> m (b, 'Auto' m a b))
 @

 Or, for 'Auto'', 'stepAuto'':

 @
 'stepAuto'' :: 'Auto'' a b -> (a -> (b, 'Auto'' a b))
 @


 'Auto's really are mostly useful because they can be composed, chained,
 and modified using their various typeclass instances, like 'Category',
 in this library.  You can build complex programs as a complex 'Auto' by
 building up smaller and smaller components.  See the tutorial for more
 information on this.

 This type also contains information on its own serialization, so you can
 serialize and re-load the internal state to binary or disk.  See the
 "serialization" section in the documentation for "Control.Auto.Core", or
 the documentation for 'mkAutoM' for more details.


 | Re-structure 'Auto' internals to use the 'Arb' ("arbitrary")
 constructors, as recursion-based mealy machines.

 Mostly here for performance comparisons and benchmarking purposes.

 | Returns a string representation of the internal constructor of the
 'Auto'.  Useful for debugging the result of compositions and functions
 and seeing how they affect the internal structure of the 'Auto'.

 In the order of efficiency, "AutoFunc"s tend to be faster than
 "AutoState"s tend to be faster than "AutoArb"s.  However, when composing

 More benchmarking is to be done to be able to rigorously say what these
 really mean, performance wise.
 morphism "transforming function", a natural transformation.

 Basically, given a function to "swap out" any @m a@ with an @m' a@, it
 swaps out the underlying monad of the 'Auto'.

 This forms a functor, so you rest assured in things like this:

 @
 hoistA id == id
 hoistA f a1 . hoistA f a2 == hoistA f (a1 . a2)
 @
 ^ monad morphism;
     the natural transformation
 | Generalizes an @'Auto'' a b@ to an @'Auto' m a b'@ for any 'Monad'
 @m@, using 'hoist'.

 You generally should be able to avoid using this if you never directly
 write any 'Auto''s and always write 'Auto m' parameterized over all
 can use this.

 | Force the serializing components of an 'Auto'.

 TODO: Test if this really works
 $serializing

 The 'Auto' type offers an interface in which you can serialize

 You can "freeze" any 'Auto' into a 'ByteString' using 'encodeAuto' (or,
 there's 'saveAuto'.

 You can "resume" any 'Auto' from a 'ByteString' using 'decodeAuto' (or,
 if you want the raw 'Get' for some reason, there's 'resumeAuto').

 if you call 'decodeAuto' on a "fresh 'Auto'", it'll decode
 a 'ByteString' into /that 'Auto', but "resumed"/.  That is, it'll "fast
 forward" that 'Auto' into the state it was when it was saved.

 numbers it has seen so far.

 >>> let a = sumFrom 0
 >>> let (_, a'') = stepAuto' a' 10


 >>> let bs            = encodeAuto a''

 To "resume" / "load" it, I can use 'decodeAuto' to "resume" the

 >>> let (Right resumed) = decodeAuto a bs

 Note that all of these would have had the same result:

 >>> let (Right resumed) = decodeAuto a'  bs
 >>> let (Right resumed) = decodeAuto a'' bs
 >>> let (Right resumed) = decodeAuto (sumFrom 0) bs

 I mean, after all, if 'decodeAuto' "fast forwards" an 'Auto' to the
 state it was at when it was frozen...then all of these should really be
 resumed to the same point, right?

 an 'Auto' and creates a "blueprint" from that 'Auto', on how to "load
 it"; the blueprint contains what the form of the internal state is, and
 their offets in the 'ByteString'.  So in the above, 'a', 'a'', 'a''',
 and @'sumFrom' 0@ all have the same "blueprint" --- their internal
 states are of the same structure.

 Now, the /magic/ of this all is that combining and transforming 'Auto's
 with the combinators in this library will also /compose serialization
 strategies/ .... complex 'Auto's and combinations/chains of 'Auto's
 create serialization strategies "for free".  The
 <-examples auto-examples> repo has a lot
 of examples that use this  to great effect, serializing entire
 applications and entire chat bots without writing any serialization
 code; it all does it "by itself".  Be sure to read about the caveats in
 the
 < tutorial>.

 Some specific 'Auto's (indicated by a naming convention) might choose to
 have internal state, yet ignore it when saving/loading.  So, saving it
 actaully saves no state, and "resuming" it really doesn't do anything.
 That is, @'decodeAuto' a_ bs = Right a_@.  There isn't a real way to
 identify from the type of the 'Auto' if it will properly save/resume or
 not, so you have to keep track of this yourself.  In all of the 'Auto'
 by naming convention to be a non-resuming 'Auto'.

 In your own compositions, if you are sure to always use resuming
 'Auto's, your composition will also be properly resuming...so you don't
 have to worry about this!  You shouldn't really ever be "surprised",
 because you'll always explicitly chose the resuming version for 'Auto's
 you want to resume, and the non-resuming version for those you don't.

 Now, /making/ or /writing/ your own generic 'Auto' combinators and
 transformers that take advantage of serialization is a bit of
 a headache.  When you can, you might be able to make combinators out of
 the existing functions in this library.  Sometimes, however, it's
 unavoidable.  If you are making your own 'Auto' combinators, making sure
 serialization works as expected is tough; check out the documentation
 for 'mkAutoM' for more details.

 | Encode an 'Auto' and its internal state into a 'ByteString'.
 a 'Left' if the deserialization is not possible.
 | Returns a 'Get' from an 'Auto' ---  instructions (from
 saved 'Auto', in the originally saved state.
- instructions ( from " Data . Serialize " ) on how to
 encoding.  It can later be reloaded and "resumed" by
 'resumeAuto'/'decodeAuto'.
 | Takes an 'Auto' that is serializable/resumable and returns an 'Auto'
 that is not.  That is, when it is "saved", saves no data, and when it is
 "resumed", resets itself back to the initial configuration every time;
 in other words, @'decodeAuto' (unserialize a) bs = Right (unserialize
 a)@.  Trying to "resume" it will just always give itself, unchanged.

 That is, given an @'Auto' m a b@, returns a function that takes an @a@

 This is the main way of running an 'Auto' "step by step", so if you have
 some sort of game loop that updates everything every "tick", this is
 what you're looking for.  At every loop, gather input @a@, feed it into
 next time.

 Here,

 @
 stepAuto :: Auto Identity Int Int
          -> (Int -> Identity (Int, Auto Identity Int Int))
 @

 Every time you "step", you give it an 'Int' and get a resulting 'Int'
 (the cumulative sum) and the "updated 'Auto'", with the updated
 accumulator.

         a0 = sumFrom 0
 run with 4
 >>> res1
 the cumulative sum , 4
 run with 5
 >>> res2
 the cumulative sum , 4 + 5
 run with 3
 >>> res3
 the cumulative sum , 4 + 5 + 3

 By the way, for the case where your 'Auto' is under 'Identity', we have
 a type synomym 'Auto''...and a convenience function to make "running" it
 more streamlined:

 >>> let a0 :: Auto' Int Int
         a0 = sumFrom 0
 run with 4
 >>> res1
 the cumulative sum , 4
 run with 5
 >>> res2
 the cumulative sum , 4 + 5
 run with 3
 >>> res3
 the cumulative sum , 4 + 5 + 3

 But, if your 'Auto' actaully has effects when being stepped, 'stepAuto'
 will execute them:

 >>> let a0 :: Auto IO Int Int
         a0 = effect (putStrLn "hey!") *> sumFrom 0
 run with 4
 hey!         -- IO effect
 >>> res1
 the cumulative sum , 4
 run with 5
 hey!         -- IO effect
 >>> res2
 the cumulative sum , 4 + 5
 run with 3
 hey!         -- IO effect
 >>> res3
 the cumulative sum , 4 + 5 + 3

 ignores its input and just executes @'putStrLn' "hey"@ every time it is
 for the "final" output at the end, we only return the output of the

 then 'stepAuto' lets you "run" it.


 ^ the 'Auto' to step
 ^ the input
 ^ the output, and the updated 'Auto''.

 That is, given an @'Auto'' a b@, returns a function that takes an @a@

 See 'stepAuto' documentation for motivations, use cases, and more
 details.  You can use this instead of 'stepAuto' when your underyling
 monad is 'Identity', and your 'Auto' doesn't produce any effects.

 cumulative sum of the inputs

 @
 stepAuto' :: Auto' Int Int
           -> (Int -> (Int, Auto' Int Int))
 @

 Every time you "step", you give it an 'Int' and get a resulting 'Int'
 (the cumulative sum) and the "updated 'Auto''", with the updated
 accumulator.

 >>> let a0 :: Auto' Int Int
         a0 = sumFrom 0
 run with 4
 >>> res1
 the cumulative sum , 4
 run with 5
 >>> res2
 the cumulative sum , 4 + 5
 run with 3
 >>> res3
 the cumulative sum , 4 + 5 + 3

 If you think of an @'Auto'' a b@ as a "stateful function" @a -> b@,
 then 'stepAuto'' lets you "run" it.


 ^ the 'Auto'' to step
 ^ the input
 ^ the output, and the updated 'Auto''
 | In theory, "purifying" an 'Auto''" should prep it for faster
 evaluation when used with 'stepAuto'' or 'streamAuto''.  But the
 benchmarks have not been run yet, so stay tuned!

 TODO: Benchmark
 | Like 'stepAuto', but drops the "next 'Auto'" and just gives the
 result.
 ^ 'Auto' to run
 ^ input
 ^ output
 | Like 'stepAuto'', but drops the "next 'Auto''" and just gives the
 result.  'evalAuto' for 'Auto''.
 ^ 'Auto' to run
 ^ input
 ^ output
 | Like 'stepAuto', but drops the result and just gives the "updated
 'Auto'".
 ^ 'Auto' to run
 ^ input
 ^ updated 'Auto'
 | Like 'stepAuto'', but drops the result and just gives the "updated
 'Auto''".  'execAuto' for 'Auto''.
 ^ 'Auto'' to run
 ^ input
 ^ updated 'Auto''
 | A special 'Auto' that acts like the 'id' 'Auto', but forces results as
 they come through to be fully evaluated, when composed with other
 'Auto's.

 TODO: Test if this really works
 | A special 'Auto' that acts like the 'id' 'Auto', but forces results as
 they come through to be evaluated to Weak Head Normal Form, with 'seq',
 when composed with other 'Auto's.

 TODO: Test if this really works
 | Abstraction over lower-level funging with serialization; lets you
 modify the result of an 'Auto' by being able to intercept the @(b,
 'Auto' m a b)@ output and return a new output value @m c@.

 Note that this is a lot like 'fmap':

 @
 fmap :: (b -> c) -> Auto m a b -> Auto m a c
 @


 Basically experimenting with a bunch of abstractions over different
 lower-level modification of 'Auto's, because making sure the
 serialization works as planned can be a bit difficult.

 ^ intercepting function
 compMAuto g f = AutoArbM undefined
                          undefined
                              Output y f' <- stepAuto f x
                              undefined
 doesn't work like you'd think lol.
 serialForcer = a
   where
                         in  forceSerial a `seq` outp
 | Construct an 'Auto' by explicity giving its serialization,
 deserialization, and the function from @a@ to a @b@ and "updated
 'Auto'".

 Ideally, you wouldn't have to use this unless you are making your own
 framework.  Try your best to make what you want by assembling

 See 'mkAutoM' for more detailed instructions on doing this right.
 ^ resuming/loading 'Get'
 ^ saving 'Put'
 ^ step function
 | Construct an 'Auto' by explicitly giving its serializiation,
 deserialization, and the (monadic) function from @a@ to a @b@ and the
 "updated 'Auto'".

 See the "serialization" section in the "Control.Auto.Core" module for
 more information.

 Ideally, you wouldn't have to use this unless you are making your own
 framework.  Try your best to make what you want by assembling

 But sometimes you have to write your own combinators, and you're going
 to have to use 'mkAutoM' to make it work.

 Sometimes, it's simple:

 @
 fmap :: (a -> b) -> Auto r a -> Auto r b
 fmap f a0 = mkAutoM (do aResumed <- resumeAuto a0
                     (saveAuto a0)
                         (y, a1) <- stepAuto a0 x
                         return (f y, fmap f a1)
 @


 Also another nice "simple" example is:

 @
 catchA :: Exception e
        => Auto IO a b
        -> Auto IO a (Either e b)
 catchA a = mkAutoM (do aResumed <- resumeAuto a
                        return (catchA aResumed) )
                    (saveAuto a)
                      eya' <- try $ stepAuto a x
                      case eya' of
                        Right (y, a') -> return (Right y, catchA a')
                        Left e        -> return (Left e , catchA a )
 @

 Which is basically the same principle, in terms of serializing and
 resuming strategies.

 When you have "switching" --- things that behave like different 'Auto's
 at different points in time --- then things get a little complicated,
 because you have to figure out which 'Auto' to resume.

 For example, let's look at the source of '-?>':

 @
       => Interval m a b   -- ^ initial behavior
       -> Interval m a b   -- ^ final behavior, when the initial
                           --   behavior turns off.
       -> Interval m a b
 a1 -?> a2 = mkAutoM l s t
   where
     l = do
       flag <- get
       if flag
         then resumeAuto (switched a2)
         else (-?> a2) <$> resumeAuto a1
     s = put False *> saveAuto a1
     t x = do
       (y1, a1') <- stepAuto a1 x
       case y1 of
         Just _  ->
           return (y1, a1' -?> a2)
         Nothing -> do
           (y, a2') <- stepAuto a2 x
           return (y, switched a2')
     switched a = mkAutoM l
                          (put True  *> saveAuto a)
                            (y, a') <- stepAuto a x
                            return (y, switched a')
 @

 We have to invent a serialization and reloading scheme, taking into

      @a2@'s current.

 give us @l@.  So the 'Get' we use --- the process we use to resume the
 entire @a1 '-?>' a2@, will /start/ at the initial 'Get'/loading
 function, @l@ here.  We have to encode our branching and
 resuming/serialization scheme into the initial, front-facing @l@.  So
 @l@ has to check for the flag, and if the flag is true, load in the data
 for the switched state; otherwise, load in the data for the pre-switched
 state.

 Not all of them are this tricky.  Mostly "switching" combinators will be
 tricky, because switching means changing what you are serializing.

 This one might be considerably easier, because of 'mapM':

 @
         => a                -- ^ default input value
         -> [Auto m a b]     -- ^ 'Auto's to zip up
         -> Auto m [a] [b]
 zipAuto x0 as = mkAutoM (zipAuto x0 <$> mapM resumeAuto as)
                         (mapM_ saveAuto as)
                         $ \xs -> do
                             let (ys, as') = unzip res
 @

 To serialize, we basically sequence 'saveAuto' over all of the internal
- serialize each of their serialization data one - by - one one
 after the other in our binary.

 To load, we do the same thing; we go over every 'Auto' in @as@ and
 'resumeAuto' it, and then collect the results in a list --- a list of
 resumed 'Auto's.  And then we apply @'zipAuto' x0@ to that list of

 So, it might be complicated.  In the end, it might be all worth it, too,
 to have implicit serialization compose like this.  Think about your
 to serialize at every step, and remember that it's _the initial_
 "resuming" function that has to "resume everything"...it's not the
 resuming function that exists when you finally save your 'Auto', it's
 the resuming 'Get' that was there /at the beginning/.  For '-?>', the

 And of course as always, test.

 If you need to make your own combinator or transformer but are having
 trouble with the serializtion, feel free to contact me at
 <>, on freenode at /#haskell/ or /#haskell-auto/, open
 a < github issue>, etc.  Just
 contact me somehow, I'll be happy to help!

 ^ resuming/loading 'Get'
 ^ saving 'Put'
 ^ (monadic) step function
 | Like 'mkAuto', but without any way of meaningful serializing or
 deserializing.

 Be careful!  This 'Auto' can still carry arbitrary internal state, but
 it cannot be meaningfully serialized or re-loaded/resumed.  You can
 still pretend to do so using
 'resumeAuto'/'saveAuto'/'encodeAuto'/'decodeAuto' (and the type system
 won't stop you), but when you try to "resume"/decode it, its state will
 be lost.
 ^ step function
# INLINE mkAuto_ #
 | Like 'mkAutoM', but without any way of meaningful serializing or
 deserializing.

 Be careful!  This 'Auto' can still carry arbitrary internal state, but
 it cannot be meaningfully serialized or re-loaded/resumed.  You can
 still pretend to do so using
 'resumeAuto'/'saveAuto'/'encodeAuto'/'decodeAuto' (and the type system
 won't stop you), but when you try to "resume"/decode it, its state will
 be reset.
 ^ (monadic) step function
# INLINE mkAutoM_ #
 | Construct the 'Auto' whose output is always the given value, ignoring
 its input.

 Provided for API constency, but you should really be using 'pure' from
 the 'Applicative' instance, from "Control.Applicative", which does the
 same thing.
 ^ constant value to be outputted
 | Construct the 'Auto' that always "executes" the given monadic value at
 every step, yielding the result as its output and ignoring its input.

 Provided for API consistency, but you shold really be using 'effect'
 from "Control.Auto.Effects", which does the same thing.
 ^ monadic action to be executed at every step
 | Construct a stateless 'Auto' that simply applies the given (pure)
 function to every input, yielding the output.  The output stream is just
 the result of applying the function to every input.

 prop> streamAuto' (mkFunc f) = map f

 instance, from "Control.Arrow".
 ^ pure function
 | Construct a stateless 'Auto' that simply applies and executes the givne
 (monadic) function to every input, yielding the output.  The output
 stream is the result of applying the function to every input,
 executing/sequencing the action, and returning the returned value.

 prop> streamAuto (mkFuncM f) = mapM f

 It's recommended that you use 'arrM' from "Control.Auto.Effects".  This
 is only really provided for consistency.
 ^ "monadic" function
 gives you an @'Auto' m a b@, for any 'Monad' @m@.  At every step, it
 takes in the @a@ input, runs the function with the stored internal
 You have to intialize it with an initial state, of course.

 From the "stream transformer" point of view, this is rougly equivalent
 to 'mapAccumL' from "Data.List", with the function's arguments and
 results in the backwards order.


 Try not to use this if it's ever avoidable, unless you're a framework
 developer or something.  Try make something by combining/composing the
 various 'Auto' combinators.

 either write a meaningful one, provide the serialization methods
 manually with 'mkState'', or throw away serializability and use
 'mkState_'.
 ^ state transformer
 ^ intial state
 @a@ input, runs the function with the stored internal state and
 the new, updated state.  Must be initialized with an initial state.

 Try not to use this if it's ever avoidable, unless you're a framework
 developer or something.  Try make something by combining/composing the
 various 'Auto' combinators.

 This version is a wrapper around 'mkAuto', that keeps track of the
 serialization and re-loading of the internal state for you, so you don't
 have to deal with it explicitly.

 either write a meaningful one, provide the serialization methods
 manually with 'mkStateM'', or throw away serializability and use
 'mkStateM_'.
 ^ (monadic) state transformer
 ^ initial state
 and putting the state.

 See 'mkState' for more details.
 ^ 'Get'; strategy for reading and deserializing the state
 ^ 'Put'; strategy for serializing given state
 ^ state transformer
 ^ intial state
 | A version of 'mkStateM', where the internal state doesn't have
 and putting the state.

 See 'mkStateM' for more details.
 ^ 'Get'; strategy for reading and deserializing the state
 ^ 'Put'; strategy for serializing given state
 ^ (monadic) state transformer
 ^ initial state
 can be "saved" and "loaded", but the state is lost in the process.

 See 'mkState' for more details.

 ^ state transformer
 ^ initial state
# INLINE mkState_ #
 | A version of 'mkStateM', where the internal state isn't serialized.
 It can be "saved" and "loaded", but the state is lost in the process.

 See 'mkStateM' for more details.

 ^ (monadic) state transformer
 ^ initial state
 | Construct an 'Auto' from a "folding" function: @b -> a -> b@ yields an
 an internal accumulator that is "updated" with an @a@ at every step.
 Must be given an initial accumulator.

 Example: an 'Auto' that sums up all of its input.

 >>> sum2

 should either write a meaningful one, or throw away serializability and
 use 'accum_'.
 ^ accumulating function
 ^ initial accumulator
 | Construct an 'Auto' from a "monadic" "folding" function: @b -> a ->
 (if it existed).  here is an internal accumulator that is "updated" with
 an input @a@ with the result of the executed @m b@ at every step.  Must
 be given an initial accumulator.

 See 'accum' for more details.

 should either write a meaningful one, or throw away serializability and
 use 'accumM_'.
 ^ (monadic) accumulating function
 ^ initial accumulator
 | A version of 'accum', where the internal accumulator isn't
 serialized. It can be "saved" and "loaded", but the state is lost in the
 process.

 See 'accum' for more details.

 instance.
 ^ accumulating function
 ^ intial accumulator
 | A version of 'accumM_, where the internal accumulator isn't
 serialized. It can be "saved" and "loaded", but the state is lost in the
 process.

 See 'accumM' for more details.

 instance.
 ^ (monadic) accumulating function
 ^ initial accumulator
# INLINE accumM_ #
 state of the accumulator, before applying the folding function. Useful
 in recursive bindings.

 >>> sum2
 [13,14,16,19,23,28,34,41,49,58]

 (Compare with the example in 'accum')

 "decoded" with 'streamAuto'':

 >>> let myScanl f z = streamAuto' (accumD f z)
 [0,3,6,10,15,21,28,36,45,55]
 [0,3,6,10,15,21,28,36,45]

 The only difference is that you don't get the last element.  (You could
 force it out, if you wanted, by feeding any nonsense value in --- even
 'undefined'! --- and getting the result)

 ^ accumulating function
 ^ initial accumulator
 state of the accumulator, before applying the folding function. Useful
 in recursive bindings.
 ^ (monadic) accumulating function
 ^ initial accumulator
 | The non-resuming/non-serializing version of 'accumD'.
 ^ accumulating function
 ^ intial accumulator
# INLINE accumD_ #
 | The non-resuming/non-serializing version of 'accumMD'.
 ^ (monadic) accumulating function
 ^ initial accumulator
 | Maps over the output stream of the 'Auto'.

 | 'pure' creates the "constant" 'Auto':

 ["foo","foo","foo","foo","foo"]

 '<*>' and 'liftA2' etc. give you the ability to fork the input stream
 over many 'Auto's, and recombine the results:


 For effectful 'Auto', you can imagine '*>' as "forking" the input stream

 @
 'effect' 'print' *> 'sumFrom' 0
 @

 input to 'IO' at every step.

 i give up!
# INLINE (<*>) #
 fork the input through each one and "squish" their results together
 inside the 'Alternative' context.  See 'runTraversableA' for similar use
 cases.

 Nothing
 Just [-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
 Just [-1,2,-3,4,-5,6,-7,8,-9,10]

 | Gives the ability to "compose" two 'Auto's; feeds the input stream
# INLINE (.) #
 | 'lmap' lets you map over the /input/ stream, and 'rmap' lets you map
 is 'fmap'.
 | See 'Arrow' instance.
 | Gives us 'arr', which is a "stateless" 'Auto' that behaves just like
 a function; its outputs are the function applied the corresponding
 inputs.

 [-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]

 field in an input stream that is tuples...and also allows 'Auto's to run
 side-by-side on an input stream of tuples (run each on either tuple
 field).

 [(4,True),(10,False),(18,False),(25,True)]
 [1,3,15,30]
 [(4,1),(10,3),(18,15),(25,30)]

 Most importantly, however, allows for "proc" notation; see the
 < tutorial>!
 for more details.

 | Allows you to have an 'Auto' only act on "some" inputs (only on
 'Left's, for example), and be "paused" otherwise.

 >>> streamAuto' (sumFrom 0) [1,4,2,5]

 Again mostly useful for "proc" notation, with branching.

# INLINE left #
 | Finds the fixed point of self-referential 'Auto's (for example,
 feeding the output stream of an 'Auto' to itself).  Mostly used with
 proc notation to allow recursive bindings.
 Utility instances
 | Fork the input stream and '<>' the outputs.  See the 'Monoid'
 instance.

 ["helhello","worhelloworld","goohelloworldgood","byehelloworldgoodbye"]
 | String literals in code will be 'Auto's that constanty produce that
 string.

 > " world " ) $ repeat ( )
 ["hello","hello","world","world","world","world"]
 | Fork the input stream and add, multiply, etc. the outputs.  'negate'
 will negate the ouptput stream.  'fromInteger' will be a constant stream
 code:


 | Fork the input stream and divide the outputs.  'recip' maps 'recip' to
 the output stream; 'fromRational' will be a constant stream of that
 | A bunch of constant producers, mappers-of-output-streams, and
 forks-and-recombiners.
 Utility functions
# LANGUAGE CPP #
# LANGUAGE ExistentialQuantification #
# LANGUAGE TupleSections #
# OPTIONS_HADDOCK not - home #

  License      : MIT
  Maintainer   : 

module Control.Auto.Core (
    Auto
  , Auto'
  , autoConstr
  , toArb
  , purifyAuto
  , stepAuto
  , stepAuto'
  , evalAuto
  , evalAuto'
  , execAuto
  , execAuto'
  * * 
  , encodeAuto
  , decodeAuto
  , saveAuto
  , resumeAuto
  , unserialize
  , hoistA
  , generalizeA
  , interceptO
  , mkConst
  , mkConstM
  , mkFunc
  , mkFuncM
  * * from State transformers
  , mkState
  , mkState_
  , mkStateM
  , mkStateM_
  , mkState'
  , mkStateM'
  , accum
  , accum_
  , accumM
  , accumM_
  , accumD
  , accumD_
  , accumMD
  , accumMD_
  , mkAuto
  , mkAuto_
  , mkAutoM
  , mkAutoM_
  , forceSerial
  , forcer
  , seqer
  ) where

import Control.Applicative
import Control.Arrow
import Control.Category
import Control.DeepSeq
import Control.Monad hiding   (sequence)
import Control.Monad.Fix
import Data.ByteString hiding (empty)
import Data.Functor.Identity
import Data.Orphans           ()
import Data.Profunctor
import Data.Semigroup
import Data.Serialize
import Data.String
import Data.Traversable
import Prelude hiding         ((.), id, sequence)

#if MIN_VERSION_base(4,7,0)
import Data.Typeable
#endif


  represents / denotes a /a relationship/ between an input and an
  transformer from any ' Auto ' : if @a : : ' Auto ' m a b@ , ' streamAuto ' lets
  you turn it into an @[a ] - > m [ b]@.   " Give me a stream of @a@s , one at
  your stream of @a@s . "
  ' streamAuto ' : :   = > ' Auto ' m a b - > ( [ a ] - > m [ b ] )
  type Auto ' = Auto Identity
  So if you had an @a : : ' Auto '' a b@ , you can use ' streamAuto '' to
  " unwrap " the inner stream transformer , @[a ] - > [ b]@.
  get a @b@ and an " updated ' Auto'"/function with updated state .
  " Give me an @a@ and I 'll give you a @b@ and your " updated " ' Auto ' " .
  ' Applicative ' , ' Functor ' , ' Arrow ' , etc . , and also with the combinators
data Auto m a b =           AutoFunc    !(a -> b)
                |           AutoFuncM   !(a -> m b)
                | forall s. AutoState   (Get s, s -> Put) !(a -> s -> (b, s))   !s
                | forall s. AutoStateM  (Get s, s -> Put) !(a -> s -> m (b, s)) !s
                |           AutoArb     (Get (Auto m a b)) Put !(a -> (b, Auto m a b))
                |           AutoArbM    (Get (Auto m a b)) Put !(a -> m (b, Auto m a b))
#if MIN_VERSION_base(4,7,0)
                deriving ( Typeable )
#endif


  | Special case of ' Auto ' where the underlying '  ' is ' Identity ' .
  Instead of " wrapping " an @[a ] - > m [  , it " wraps " an @[a ] - > [ b]@.
type Auto'   = Auto Identity


toArb :: Monad m => Auto m a b -> Auto m a b
toArb a = a_
  where
    a_ = case a of
           AutoFunc f  -> AutoArb  (pure a_)
                                   (return ())
                                 $ \x -> (f x, a_)
           AutoFuncM f -> AutoArbM (pure a_)
                                   (return ())
                                 $ \x -> liftM (, a_) (f x)
           AutoState gp@(g,p) f s  ->
               let a' s' = AutoArb (toArb . AutoState gp f <$> g)
                                   (p s')
                                 $ \x -> let (y, s'') = f x s'
                                         in  (y, a' s'')
               in  a' s
           AutoStateM gp@(g,p) f s ->
               let a' s' = AutoArbM (toArb . AutoStateM gp f <$> g)
                                    (p s)
                                  $ \x -> do
                                      (y, s'') <- f x s'
                                      return (y, a' s'')
               in  a' s
           AutoArb l s f -> AutoArb (toArb <$> l)
                                    s
                                  $ \x -> let (y, a') = f x
                                          in  (y, toArb a')
           AutoArbM l s f -> AutoArbM (toArb <$> l)
                                      s
                                    $ \x -> do
                                        (y, a') <- f x
                                        return (y, toArb a')


  one with the other ( using ' Category ' or ' Applicative ' ) , the two have to
  be " reduced " to the greatest common denominator ; composing an " AutoFunc "
  with an " AutoArb " produces an "  " .
autoConstr :: Auto m a b -> String
autoConstr (AutoFunc {})   = "AutoFunc"
autoConstr (AutoFuncM {})  = "AutoFuncM"
autoConstr (AutoState {})  = "AutoState"
autoConstr (AutoStateM {}) = "AutoStateM"
autoConstr (AutoArb {})    = "AutoArb"
autoConstr (AutoArbM {})   = "AutoArbM"

  | Swaps out the underlying '  ' of an ' Auto ' using the given monad
hoistA :: (Monad m, Monad m')
       -> Auto m a b
       -> Auto m' a b
hoistA _ (AutoFunc f)        = AutoFunc f
hoistA g (AutoFuncM f)       = AutoFuncM (g . f)
hoistA _ (AutoState gp f s)  = AutoState gp f s
hoistA g (AutoStateM gp f s) = AutoStateM gp (\x s' -> g (f x s')) s
hoistA g (AutoArb gt pt f)   = AutoArb (fmap (hoistA g) gt)
                                       pt
                                       $ \x -> let (y, a') = f x
                                               in  (y, hoistA g a')
hoistA g (AutoArbM gt pt f)  = AutoArbM (fmap (hoistA g) gt)
                                        pt
                                        $ \x -> g $ do
                                            (y, a') <- f x
                                            return (y, hoistA g a')

  ' Monad 's , but ... in case you import one from a library or something , you
generalizeA :: Monad m => Auto' a b -> Auto m a b
generalizeA = hoistA (return . runIdentity)

forceSerial :: Auto m a b -> Auto m a b
forceSerial a = case a of
                  AutoArb _ l s  -> l `seq` s `seq` a
                  AutoArbM _ l s -> l `seq` s `seq` a
                  _              -> a

  ( " freeze " ) and " resume " an Auto , in ' ByteString ' ( binary ) form .
  if you want the raw ' Put ' ( from " Data . Serialize " ) for some reason ,
  Note ' decodeAuto ' and ' resumeAuto ' " resume " a  ' Auto'/.   That is ,
  For example , let 's say I have @a = ' sumFrom ' 0@ , the ' Auto ' whose output
  is the cumulative sum of all of its inputs so far . If I feed it 3 and
  10 , it 'll have its internal accumulator as 13 , keeping track of all the
  > > > let ( _ , a ' ) = stepAuto ' a   3
  I can then use ' encodeAuto ' to " freeze"/"save " the ' Auto ' into the
  ' ByteString ' @bs@ :
      , ' a ' was our original ' Auto ' , the summer
  ' Auto ' with a starting accumulator of 0 .   We use ' decodeAuto ' to
  " resume " it , with and resume it with its internal accumulator at 13 .
  > > > let ( y , _ ) = stepAuto ' resumed 0
  13
  One way you can think about it is that ' resumeAuto ' / ' decodeAuto ' takes
  " included " in this library , any ' Auto ' whose name /does not/ end in @_@
  /will serialize and resume/.   An ' Auto ' whose name ends in @_@ is taken

encodeAuto :: Auto m a b -> ByteString
encodeAuto = runPut . saveAuto
# INLINE encodeAuto #

  | " Resume " an ' Auto ' from its ' ByteString ' serialization , giving
decodeAuto :: Auto m a b -> ByteString -> Either String (Auto m a b)
decodeAuto = runGet . resumeAuto
# INLINE decodeAuto #

  " Data . Serialize " ) on taking a ByteString and " restoring " the originally
resumeAuto :: Auto m a b -> Get (Auto m a b)
resumeAuto a = case a of
                 AutoState gp f _  -> AutoState  gp f <$> fst gp
                 AutoStateM gp f _ -> AutoStateM gp f <$> fst gp
                 AutoArb g _ _     -> g
                 AutoArbM g _ _    -> g
                 _                 -> return a
# INLINE resumeAuto #

  " freeze " the ' Auto ' , with its internal state , and save it to a binary
saveAuto :: Auto m a b -> Put
saveAuto a = case a of
               AutoState (_, p) _ s  -> p s
               AutoStateM (_, p) _ s -> p s
               AutoArb _ p _         -> p
               AutoArbM _ p _        -> p
               _                     -> return ()
# INLINE saveAuto #

unserialize :: Monad m => Auto m a b -> Auto m a b
unserialize a =
    case a of
        AutoFunc _       -> a
        AutoFuncM _      -> a
        AutoState _ f s  -> AutoState (pure s, const (put ())) f s
        AutoStateM _ f s -> AutoStateM (pure s, const (put ())) f s
        AutoArb _ _ f    -> AutoArb (pure a) (put ()) (second unserialize . f)
        AutoArbM _ _ f   -> AutoArbM (pure a) (put ()) (liftM (second unserialize) . f)

  | " Runs " the ' Auto ' through one step .
  and returns a @b@ and an " updated"/"next " ' Auto ' ; an @a - > m ( b , ' Auto '
  m a b)@.
  the ' Auto ' , " render " the result @b@ , and get your new ' Auto ' to run the
  Here is an example with @'sumFrom ' 0@ , the ' Auto ' whose output is the
  cumulative sum of the inputs , and an underying monad of 
  > > > let a0 : : Auto Identity Int Int
  ( Here , @'effect ' ( ' putStrLn ' " hey")@ is an @'Auto ' IO Int ( ) @ , which
  run .   When we use ' * > ' from " Control . Applicative " , we " combine " the two
  ' Auto 's together and run them /both/ on each input ( 4 , 5 , 3 ... ) ... but
  second one , @'sumFrom ' 0@ ( 5 , 9 , 12 ... ) )
  If you think of an @'Auto ' m a b@ as a " stateful function " @a - > m b@ ,
  In order to directly run an ' Auto ' on a stream , an @[a]@ , use
  ' streamAuto ' .   That gives you an @[a ] - > m [ b]@.
stepAuto :: Monad m
stepAuto a x = case a of
                 AutoFunc f        ->
                     return (f x, a)
                 AutoFuncM f       -> do
                     y <- f x
                     return (y, a)
                 AutoState gp f s  ->
                     let (y, s') = f x s
                         a'      = AutoState gp f s'
                     in  return (y, a')
                 AutoStateM gp f s -> do
                     (y, s') <- f x s
                     let a' = AutoStateM gp f s'
                     return (y, a')
                 AutoArb _ _ f     -> return (f x)
                 AutoArbM _ _ f    -> f x
# INLINE stepAuto #

  | " Runs " an ' Auto '' through one step .
  and returns a @b@ and an " updated"/"next " ' Auto '' ; an @a - > ( b , ' Auto ''
  a b)@.
  Here is an example with @'sumFrom ' 0@ , the ' Auto '' whose output is the
  In order to directly run an ' Auto '' on a stream , an @[a]@ , use
  ' streamAuto '' .   That gives you an @[a ] - > [ b]@.
stepAuto' a x = case a of
                  AutoFunc f        -> (f x, a)
                  AutoFuncM f       -> (runIdentity (f x), a)
                  AutoState gp f s  -> let (y, s') = f x s
                                           a'      = AutoState gp f s'
                                       in  (y, a')
                  AutoStateM gp f s -> let (y, s') = runIdentity (f x s)
                                           a'      = AutoStateM gp f s'
                                       in  (y, a')
                  AutoArb _ _ f     -> f x
                  AutoArbM _ _ f    -> runIdentity (f x)
# INLINE stepAuto ' #

purifyAuto :: Auto' a b -> Auto' a b
purifyAuto a@(AutoFunc {})     = a
purifyAuto (AutoFuncM f)       = AutoFunc (runIdentity . f)
purifyAuto a@(AutoState {})    = a
purifyAuto (AutoStateM gp f s) = AutoState gp (\x s' -> runIdentity (f x s')) s
purifyAuto (AutoArb g p f)     = AutoArb (purifyAuto <$> g)
                                         p
                                       $ \x -> let (y, a') = f x
                                               in  (y, purifyAuto a')
purifyAuto (AutoArbM g p f)    = AutoArb (purifyAuto <$> g)
                                         p
                                       $ \x -> let (y, a') = runIdentity (f x)
                                               in  (y, purifyAuto a')

evalAuto :: Monad m
evalAuto a = liftM fst . stepAuto a

evalAuto' a = fst . stepAuto' a

execAuto :: Monad m
execAuto a = liftM snd . stepAuto a

execAuto' a = snd . stepAuto' a

forcer :: NFData a => Auto m a a
forcer = mkAuto_ $ \x -> x `deepseq` (x, forcer)
# INLINE forcer #

seqer :: Auto m a a
seqer = mkAuto_ $ \x -> x `seq` (x, seqer)
# INLINE seqer #

  Except gives you access to both the @b@ and the " updated ' Auto ' " ;
  instead of an @b - > c@ , you get to pass a @(b , ' Auto ' m a b ) - > m c@.
interceptO :: Monad m
           -> Auto m a b
           -> Auto m a c
interceptO f = go
  where
    go a0 = mkAutoM (go <$> resumeAuto a0)
                    (saveAuto a0)
                  $ \x -> do
                        o@(_, a1) <- stepAuto a0 x
                        y <- f o
                        return (y, go a1)

  compMAuto : : (   , Monad m ' ) = > Auto m b ( m ' c ) - > Auto m a ( m ' b ) - > Auto m a ( m ' c )
                           $ \x - > do


  serialForcer : :   = > Auto m a a
      a = mkAuto _ $ \x - > let outp = Output x a

  primtives together .   Working with serilization directly is hard .
       -> Auto m a b
mkAuto = AutoArb
# INLINE mkAuto #

  primtives together .
                          return ( fmap f aResumed )   )
                      $ \x - > do
  Serializing @'fmap ' f a0@ is just the same as serializing @a0@.   And to
  resume it , we resume @a0@ to get a resumed version of @a0@ , and then we
  apply @'fmap ' f@ to the ' Auto ' that we resumed .
                   $ \x - > do
  ( - ? > ) : :  
                         $ \x - > do
  account the two states that the resulting ' Auto ' can be in :
  1 .    Initially , it is behaving like @a1@.   So , to save it , we put
       a flag saying that we are still in stage 1 ( ' False ' ) , and then
       put @a1@ 's current serialization data .
  2 .    After the switch , it is behaving like @a2@.   So , to save it , we put
       a flag saying that we are now in stage 2 ( ' True ' ) , and then put
  Now , when we /resume/ @a1 ' - ? > ' a2@ , ' resumeAuto ' on @a1 ' - ? > ' a2@ will
  zipAuto : :  
                                        repeat  )
                              return ( ys ,   as ' )
  ' Auto 's , to get our resumed @'zipAuto '  as@.
  serialization strategy first .   Step back and think about what you need
  intial @l@ had to know how to " skip ahead " .
        -> Auto m a b
mkAutoM = AutoArbM
# INLINE mkAutoM #

        -> Auto m a b
mkAuto_ f = mkAuto (pure (mkAuto_ f)) (return ()) f

         -> Auto m a b
mkAutoM_ f = mkAutoM (pure (mkAutoM_ f)) (return ()) f

        -> Auto m a b
mkConst = AutoFunc . const
# INLINE mkConst #

         -> Auto m a b
mkConstM = AutoFuncM . const
# INLINE mkConstM #

  This is rarely needed ; you should be using ' arr ' from the ' Arrow '
       -> Auto m a b
mkFunc = AutoFunc
# INLINE mkFunc #

        -> Auto m a b
mkFuncM = AutoFuncM
# INLINE mkFuncM #

  | Construct an ' Auto ' from a state transformer : an @a - > s - > ( b , s)@
  state , returns the @b@ result , and now contains the new resulting state .
  prop > streamAuto ' ( mkState f s0 ) = snd .  (     swap ( f x s ) )
  If your state @s@ does not have a ' Serialize ' instance , then you should
mkState :: Serialize s
        -> Auto m a b
mkState = AutoState (get, put)
# INLINE mkState #

  | Construct an ' Auto ' from a " monadic " state transformer : @a - > s - >
  m ( b , s)@ gives you an @'Auto ' m a b@.   At every step , it takes in the
  " executes " the @m ( b , s)@ to get the @b@ output , and stores the @s@ as
  If your state @s@ does not have a ' Serialize ' instance , then you should
mkStateM :: Serialize s
         -> Auto m a b
mkStateM = AutoStateM (get, put)
# INLINE mkStateM #

  | A version of ' mkState ' , where the internal state does n't have
  a ' Serialize ' instance , so you provide your own instructions for getting
         -> Auto m a b
mkState' = curry AutoState
# INLINE mkState ' #

  a ' Serialize ' instance , so you provide your own instructions for getting
          -> Auto m a b
mkStateM' = curry AutoStateM
# INLINE mkStateM ' #

  | A version of ' mkState ' , where the internal state is n't serialized .   It
  Useful if your state @s@ can not have a meaningful ' Serialize ' instance .
         -> Auto m a b
mkState_ f s0 = AutoState (return s0, \_ -> return ()) f s0

  Useful if your state @s@ can not have a meaningful ' Serialize ' instance .
          -> Auto m a b
mkStateM_ f s0 = AutoStateM (return s0, \_ -> return ()) f s0
# INLINE mkStateM _ #

  @'Auto ' m a b@.   Basically acts like a ' foldl ' or a '  ' .   There is
  > > > let summer =  ( + ) 0
  > > > let (  , summer ' )   = stepAuto ' summer 3
  > > > 
  3
  > > > let ( sum2 , summer '' ) = stepAuto ' summer ' 10
  13
  > > > streamAuto '   summer '' [ 1 .. 10 ]
  [  ]
  If your accumulator  does not have a ' Serialize ' instance , then you
accum :: Serialize b
      -> Auto m a b
accum f = mkState (\x s -> let y = f s x in (y, y))
# INLINE accum #

  m b@ yields an @'Auto ' m a b@.   Basically acts like a ' foldM ' or ' scanM '
  If your accumulator  does not have a ' Serialize ' instance , then you
accumM :: (Serialize b, Monad m)
       -> Auto m a b
accumM f = mkStateM (\x s -> liftM (join (,)) (f s x))
# INLINE accumM #

  Useful if your accumulator  can not have a meaningful ' Serialize '
         -> Auto m a b
accum_ f = mkState_ (\x s -> let y = f s x in (y, y))
# INLINE accum _ #

  Useful if your accumulator  can not have a meaningful ' Serialize '
accumM_ :: Monad m
          -> Auto m a b
accumM_ f = mkStateM_ (\x s -> liftM (join (,)) (f s x))

  | A " delayed " version of ' accum ' , where the first output is the initial
  > > > let summerD = accumD ( + ) 0
  > > > let (  , summerD ' )   = stepAuto ' summerD 3
  > > > 
  0
  > > > let ( sum2 , summerD '' ) = stepAuto ' summerD ' 10
  3
  > > > streamAuto '   summerD '' [ 1 .. 10 ]
  Note that this is more or less an encoding of '  ' , that can be
  > > >  ( + ) 0 [ 1 .. 10 ]
  > > > myScanl ( + ) 0 [ 1 .. 10 ]
accumD :: Serialize b
         -> Auto m a b
accumD f = mkState (\x s -> (s, f s x))
# INLINE accumD #

  | A " delayed " version of ' accumM ' , where the first output is the initial
accumMD :: (Serialize b, Monad m)
          -> Auto m a b
accumMD f = mkStateM (\x s -> liftM (s,) (f s x))
# INLINE accumMD #

          -> Auto m a b
accumD_ f = mkState_ (\x s -> (s, f s x))

accumMD_ :: Monad m
           -> Auto m a b
accumMD_ f = mkStateM_ (\x s -> liftM (s,) (f s x))
# INLINE accumMD _ #

  > > > streamAuto ' ( sumFrom 0 ) [ 1 .. 10 ]
  [ 1,3,6,10,15,21,28,36,45,55 ]
  > > > streamAuto ' ( show < $ > sumFrom 0 ) [ 1 .. 10 ]
  [ " 1","3","6","10","15","21","28","36","45","55 " ]
instance Monad m => Functor (Auto m a) where
    fmap = rmap
# INLINE fmap #

  > > > streamAuto ' ( pure " foo " ) [ 1 .. 5 ]
  > > > streamAuto ' ( sumFrom 0 ) [ 1 .. 10 ]
  [ 1 , 3 ,   6 , 10 ,   15 ]
  > > > streamAuto ' ( productFrom 1 ) [ 1 .. 10 ]
  [ 1 , 2 ,   6 , 24 , 120 ]
  > > > streamAuto ' ( liftA2 ( + ) ( sumFrom 0 ) ( productFrom 1 ) ) [ 1 .. 5 ]
  [ 2 , 5 , 12 , 34 , 135 ]
  through both , and only keeping the result of the second :
  would , for example , behave just like @'sumFrom ' 0@ , except printing the
instance Monad m => Applicative (Auto m a) where
    pure      = mkConst
# INLINE pure #
    af <*> ax = case (af, ax) of
                  (AutoFunc f, AutoFunc x)  ->
                      AutoFunc (f <*> x)
                  (AutoFunc f, AutoFuncM x) ->
                      AutoFuncM $ \i -> liftM (f i) (x i)
                  (AutoFunc f, AutoState gp x s) ->
                      AutoState gp (\i s' -> first (f i) (x i s')) s
                  (AutoFunc f, AutoStateM gp x s) ->
                      AutoStateM gp (\i s' -> liftM (first (f i)) (x i s')) s
                  (AutoFunc f, AutoArb l s x) ->
                      AutoArb (fmap (af <*>) l) s $ \i -> (f i *** (af <*>)) $ x i
                  (AutoFunc f, AutoArbM l s x) ->
                      AutoArbM (fmap (af <*>) l) s $ \i -> liftM (f i *** (af <*>)) (x i)
                  (AutoFuncM f, AutoFunc x) ->
                      AutoFuncM $ \i -> liftM ($ x i) (f i)
                  (AutoFuncM f, AutoFuncM x) ->
                      AutoFuncM $ \i -> f i `ap` x i
                  (AutoFuncM f, AutoState gp x s) ->
                      AutoStateM gp (\i s' -> liftM (($ x i s') . first) (f i)) s
                  (AutoFuncM f, AutoStateM gp x s) ->
                      AutoStateM gp (\i s' -> liftM2 first (f i) (x i s')) s
                  (AutoFuncM f, AutoArb l s x) ->
                      AutoArbM (fmap (af <*>) l) s $ \i -> liftM (($ x i) . (*** (af <*>))) (f i)
                  (AutoFuncM f, AutoArbM l s x) ->
                      AutoArbM (fmap (af <*>) l) s $ \i -> liftM2 (*** (af <*>)) (f i) (x i)
                  (AutoState gp f s, AutoFunc x) ->
                      AutoState gp (\i s' -> first ($ x i) (f i s')) s
                  (AutoState gp f s, AutoFuncM x) ->
                      AutoStateM gp (\i s' -> liftM (\x' -> first ($ x') (f i s')) (x i)) s
                  (AutoState gpf f sf, AutoState gpx x sx) ->
                      AutoState (mergeStSt gpf gpx)
                                (\i (sf', sx') -> let (f', sf'') = f i sf'
                                                      (x', sx'') = x i sx'
                                                  in  (f' x', (sf'', sx'')))
                                (sf, sx)
                  (AutoState gpf f sf, AutoStateM gpx x sx) ->
                      AutoStateM (mergeStSt gpf gpx)
                                 (\i (sf', sx') -> do let (f', sf'') = f i sf'
                                                      (x', sx'') <- x i sx'
                                                      return (f' x', (sf'', sx'')))
                                 (sf, sx)
                  (AutoStateM gp f s, AutoFunc x) ->
                      AutoStateM gp (\i s' -> liftM (first ($ x i)) (f i s')) s
                  (AutoStateM gp f s, AutoFuncM x) ->
                      AutoStateM gp (\i s' -> do (f', s'') <- f i s'
                                                 x' <- x i
                                                 return (f' x', s'')
                                    ) s
                  (AutoStateM gpf f sf, AutoState gpx x sx) ->
                      AutoStateM (mergeStSt gpf gpx)
                                 (\i (sf', sx') -> do (f', sf'') <- f i sf'
                                                      let (x', sx'') = x i sx'
                                                      return (f' x', (sf'', sx''))
                                 ) (sf, sx)
                  (AutoStateM gpf f sf, AutoStateM gpx x sx) ->
                      AutoStateM (mergeStSt gpf gpx)
                                 (\i (sf', sx') -> do (f', sf'') <- f i sf'
                                                      (x', sx'') <- x i sx'
                                                      return (f' x', (sf'', sx''))
                                 ) (sf, sx)
                  _ -> uncurry ($) <$> (af &&& ax)

  | When the underlying ' Monad'/'Applicative ' @m@ is an ' Alternative ' ,
  > > > streamAuto ( arrM ( mfilter even . Just ) ) [ 1 .. 10 ]
  > > > streamAuto ( arrM ( Just . negate ) ) [ 1 .. 10 ]
  > > > streamAuto ( arrM ( mfilter even . Just ) ) < | > arrM ( Just . negate ) ) [ 1 .. 10 ]
instance (Monad m, Alternative m) => Alternative (Auto m a) where
    empty     = mkConstM empty
    a1 <|> a2 = mkAutoM ((<|>) <$> resumeAuto a1 <*> resumeAuto a2)
                        (saveAuto a1 *> saveAuto a2)
                        $ \x -> let res1  = second (<|> a2) `liftM` stepAuto a1 x
                                    res2  = second (a1 <|>) `liftM` stepAuto a2 x
                                in  res1 <|> res2

  into the first , feeds that output stream into the second , and returns as
  a result the output stream of the second .
instance Monad m => Category (Auto m) where
    id      = mkFunc id
    ag . af = case (ag, af) of
                (AutoFunc g, AutoFunc f)          ->
                    AutoFunc   (g . f)
                (AutoFunc g, AutoFuncM f)         ->
                    AutoFuncM  (return . g <=< f)
                (AutoFunc g, AutoState gpf f s)   ->
                    AutoState gpf (\x s' -> first g (f x s')) s
                (AutoFunc g, AutoStateM gpf f s)  ->
                    AutoStateM gpf (\x s' -> liftM (first g) (f x s')) s
                (AutoFunc g, AutoArb l s f)       ->
                    AutoArb (fmap (ag .) l) s $ \x -> (g *** fmap g) (f x)
                (AutoFunc g, AutoArbM l s f)      ->
                    AutoArbM (fmap (ag .) l) s $ \x -> liftM (g *** fmap g) (f x)
                (AutoFuncM g, AutoFunc f)         ->
                    AutoFuncM (g <=< return . f)
                (AutoFuncM g, AutoFuncM f)        ->
                    AutoFuncM (g <=< f)
                (AutoFuncM g, AutoState gpf f s)  ->
                    AutoStateM gpf (\x s' -> firstM g (f x s')) s
                (AutoFuncM g, AutoStateM gpf f s) ->
                    AutoStateM gpf (\x s' -> firstM g =<< f x s') s
                (AutoFuncM g, AutoArb l s f)      ->
                    AutoArbM (fmap (ag .) l)
                             s
                           $ \x -> do
                               let (y, af') = f x
                               y' <- g y
                               return (y', ag . af')
                (AutoFuncM g, AutoArbM l s f)     ->
                    AutoArbM (fmap (ag .) l)
                             s
                           $ \x -> do
                               (y, af') <- f x
                               y' <- g y
                               return (y', ag . af')
                (AutoState gpg g sg, AutoFunc f)  ->
                    AutoState gpg (g . f) sg
                (AutoState gpg g sg, AutoFuncM f) ->
                    AutoStateM gpg (\x sg' -> liftM (`g` sg') (f x)) sg
                (AutoState gpg g sg, AutoState gpf f sf) ->
                    AutoState (mergeStSt gpg gpf)
                              (\x (sg', sf') -> let (y, sf'') = f x sf'
                                                    (z, sg'') = g y sg'
                                                in  (z, (sg'', sf'')) )
                              (sg, sf)
                (AutoState gpg g sg, AutoStateM gpf f sf) ->
                    AutoStateM (mergeStSt gpg gpf)
                               (\x (sg', sf') -> do
                                    (y, sf'') <- f x sf'
                                    let (z, sg'') = g y sg'
                                    return (z, (sg'', sf'')) )
                               (sg, sf)
                (AutoState gpg@(gg,pg) g sg, AutoArb l s f) ->
                    AutoArb (liftA2 (\sg' af' -> AutoState gpg g sg' . af') gg l)
                            (pg sg *> s)
                            $ \x -> let (y, af') = f x
                                        (z, sg') = g y sg
                                        ag'      = AutoState gpg g sg'
                                    in  (z, ag' . af')
                (AutoState gpg@(gg,pg) g sg, AutoArbM l s f) ->
                    AutoArbM (liftA2 (\sg' af' -> AutoState gpg g sg' . af') gg l)
                             (pg sg *> s)
                             $ \x -> do
                                 (y, af') <- f x
                                 let (z, sg') = g y sg
                                     ag'      = AutoState gpg g sg'
                                 return (z, ag' . af')
                (AutoStateM gpg g sg, AutoFunc f)       ->
                    AutoStateM gpg (g <=< return . f) sg
                (AutoStateM gpg g sg, AutoFuncM f)      ->
                    AutoStateM gpg (\x sg' -> flip g sg' =<< f x) sg
                (AutoStateM gpg g sg, AutoState gpf f sf) ->
                    AutoStateM (mergeStSt gpg gpf)
                               (\x (sg', sf') -> do
                                  let (y, sf'') = f x sf'
                                  (z, sg'') <- g y sg'
                                  return (z, (sg'', sf'')) )
                               (sg, sf)
                (AutoStateM gpg g sg, AutoStateM gpf f sf) ->
                    AutoStateM (mergeStSt gpg gpf)
                               (\x (sg', sf') -> do
                                  (y, sf'') <- f x sf'
                                  (z, sg'') <- g y sg'
                                  return (z, (sg'', sf'')) )
                               (sg, sf)
                (AutoStateM gpg@(gg,pg) g sg, AutoArb l s f) ->
                    AutoArbM (liftA2 (\sg' af' -> AutoStateM gpg g sg' . af') gg l)
                             (pg sg *> s)
                             $ \x -> do
                                 let (y, af') = f x
                                 (z, sg') <- g y sg
                                 let ag' = AutoStateM gpg g sg'
                                 return (z, ag' . af')
                (AutoStateM gpg@(gg,pg) g sg, AutoArbM l s f) ->
                    AutoArbM (liftA2 (\sg' af' -> AutoStateM gpg g sg' . af') gg l)
                             (pg sg *> s)
                             $ \x -> do
                                 (y, af') <- f x
                                 (z, sg') <- g y sg
                                 let ag' = AutoStateM gpg g sg'
                                 return (z, ag' . af')
                (AutoArb l s g, AutoFunc f)  ->
                    AutoArb (fmap (. af) l) s (second (. af) . g . f)
                (AutoArb l s g, AutoFuncM f) ->
                    AutoArbM (fmap (. af) l) s (return . second (. af) . g <=< f)
                (AutoArb l s g, AutoState gpf@(gf,pf) f sf) ->
                    AutoArb (liftA2 (\ag' sf' -> ag' . AutoState gpf f sf') l gf)
                            (s *> pf sf)
                            $ \x -> let (y, sf') = f x sf
                                        af'      = AutoState gpf f sf'
                                        (z, ag') = g y
                                    in  (z, ag' . af')
                (AutoArb l s g, AutoStateM gpf@(gf,pf) f sf) ->
                    AutoArbM (liftA2 (\ag' sf' -> ag' . AutoStateM gpf f sf') l gf)
                             (s *> pf sf)
                             $ \x -> do
                                 (y, sf') <- f x sf
                                 let af'      = AutoStateM gpf f sf'
                                     (z, ag') = g y
                                 return (z, ag' . af')
                (AutoArb lg sg g, AutoArb lf sf f) ->
                    AutoArb (liftA2 (.) lg lf)
                            (sg *> sf)
                            $ \x -> let (y, af') = f x
                                        (z, ag') = g y
                                    in  (z, ag' . af')
                (AutoArb lg sg g, AutoArbM lf sf f) ->
                    AutoArbM (liftA2 (.) lg lf)
                             (sg *> sf)
                             $ \x -> do
                                 (y, af') <- f x
                                 let (z, ag') = g y
                                 return (z, ag' . af')
                (AutoArbM l s g, AutoFunc f)  ->
                    AutoArbM (fmap (. af) l)
                             s
                             (liftM (second (. af)) . g . f)
                (AutoArbM l s g, AutoFuncM f) ->
                    AutoArbM (fmap (. af) l)
                             s
                             (liftM (second (. af)) . g <=< f)
                (AutoArbM l s g, AutoState gpf@(gf,pf) f sf) ->
                    AutoArbM (liftA2 (\ag' sf' -> ag' . AutoState gpf f sf') l gf)
                             (s *> pf sf)
                             $ \x -> do
                                 let (y, sf') = f x sf
                                     af'      = AutoState gpf f sf'
                                 (z, ag') <- g y
                                 return (z, ag' . af')
                (AutoArbM l s g, AutoStateM gpf@(gf,pf) f sf) ->
                    AutoArbM (liftA2 (\ag' sf' -> ag' . AutoStateM gpf f sf') l gf)
                             (s *> pf sf)
                             $ \x -> do
                                 (y, sf') <- f x sf
                                 let af' = AutoStateM gpf f sf'
                                 (z, ag') <- g y
                                 return (z, ag' . af')
                (AutoArbM lg sg g, AutoArb lf sf f) ->
                    AutoArbM (liftA2 (.) lg lf)
                             (sg *> sf)
                             $ \x -> do
                                 let (y, af') = f x
                                 (z, ag') <- g y
                                 return (z, ag' . af')
                (AutoArbM lg sg g, AutoArbM lf sf f) ->
                    AutoArbM (liftA2 (.) lg lf)
                             (sg *> sf)
                             $ \x -> do
                                 (y, af') <- f x
                                 (z, ag') <- g y
                                 return (z, ag' . af')

mergeStSt :: (Get s, s -> Put)
          -> (Get s', s' -> Put)
          -> (Get (s, s'), (s, s') -> Put)
mergeStSt (gg, pg) (gf, pf) = (liftA2 (,) gg gf, uncurry (*>) . (pg *** pf))

  over the /output/ stream .   Note that , as with all ' Profunctor 's , ' rmap '
instance Monad m => Profunctor (Auto m) where
    lmap f = a_
      where
        a_ a = case a of
                 AutoFunc fa         -> AutoFunc (fa . f)
                 AutoFuncM fa        -> AutoFuncM (fa . f)
                 AutoState gpg fa s  -> AutoState gpg (fa . f) s
                 AutoStateM gpg fa s -> AutoStateM gpg (fa . f) s
                 AutoArb l s fa      -> AutoArb (a_ <$> l)
                                                s
                                              $ \x -> let (y, a') = fa (f x)
                                                      in  (y, a_ a')
                 AutoArbM l s fa     -> AutoArbM (a_ <$> l)
                                                 s
                                              $ \x -> do
                                                  (y, a') <- fa (f x)
                                                  return (y, a_ a')
# INLINE lmap #
    rmap g = a_
      where
        a_ a = case a of
                 AutoFunc fa         -> AutoFunc (g . fa)
                 AutoFuncM fa        -> AutoFuncM (liftM g . fa)
                 AutoState gpg fa s  -> AutoState gpg (\x -> first g . fa x) s
                 AutoStateM gpg fa s -> AutoStateM gpg (\x -> liftM (first g) . fa x) s
                 AutoArb l s fa      -> AutoArb (a_ <$> l)
                                                s
                                              $ \x -> let (y, a') = fa x
                                                      in  (g y, a_ a')
                 AutoArbM l s fa     -> AutoArbM (a_ <$> l)
                                                 s
                                               $ \x -> do
                                                   (y, a') <- fa x
                                                   return (g y, a_ a')
# INLINE rmap #
    dimap f g = a_
      where
        a_ a = case a of
                 AutoFunc fa         -> AutoFunc (g . fa . f)
                 AutoFuncM fa        -> AutoFuncM (liftM g . fa . f)
                 AutoState gpg fa s  -> AutoState gpg (\x -> first g . fa (f x)) s
                 AutoStateM gpg fa s -> AutoStateM gpg (\x -> liftM (first g) . fa (f x)) s
                 AutoArb l s fa      -> AutoArb (a_ <$> l)
                                                s
                                              $ \x -> let (y, a') = fa (f x)
                                                      in  (g y, a_ a')
                 AutoArbM l s fa     -> AutoArbM (a_ <$> l)
                                                 s
                                               $ \x -> do
                                                   (y, a') <- fa (f x)
                                                   return (g y, a_ a')
# INLINE dimap #

instance Monad m => Strong (Auto m) where
    first'  = first
    second' = second

  | See ' ArrowChoice ' instance
instance Monad m => Choice (Auto m) where
    left'  = left
    right' = right

  | See '  ' instance
instance MonadFix m => Costrong (Auto m) where
    unfirst = loop

  > > > streamAuto ' ( arr negate ) [ 1 .. 10 ]
  Also allows you to have an ' Auto ' run on only the " first " or " second "
  > > > streamAuto ' ( sumFrom 0 ) [ 4,6,8,7 ]
  [ 4,10,18,25 ]
  > > > streamAuto ' ( first ( sumFrom 0 ) ) [ ( 4,True),(6,False),(8,False),(7,True ) ]
  > > > streamAuto ' ( productFrom 1 ) [ 1,3,5,2 ]
  > > > streamAuto ' ( sumFrom 0 * * * productFrom 1 ) [ ( 4,1),(6,3),(8,5),(7,2 ) ]
instance Monad m => Arrow (Auto m) where
    arr     = mkFunc
    first a = case a of
                AutoFunc f         ->
                    AutoFunc (first f)
                AutoFuncM f        ->
                    AutoFuncM (firstM f)
                AutoState gp fa s  ->
                    AutoState gp (\(x, z) -> first (,z) . fa x) s
                AutoStateM gp fa s ->
                    AutoStateM gp (\(x, z) -> liftM (first (,z)) . fa x) s
                AutoArb l s f      ->
                    AutoArb (first <$> l)
                            s
                          $ \(x, z) -> let (y, a') = f x
                                       in  ((y, z), first a')
                AutoArbM l s f     ->
                    AutoArbM (first <$> l)
                             s
                           $ \(x, z) -> do
                               (y, a') <- f x
                               return ((y, z), first a')
    second a = case a of
                 AutoFunc f         ->
                     AutoFunc (second f)
                 AutoFuncM f        ->
                     AutoFuncM (secondM f)
                 AutoState gp fa s  ->
                     AutoState gp (\(z, x) -> first (z,) . fa x) s
                 AutoStateM gp fa s ->
                     AutoStateM gp (\(z, x) -> liftM (first (z,)) . fa x) s
                 AutoArb l s f      ->
                     AutoArb (second <$> l)
                             s
                           $ \(z, x) -> let (y, a') = f x
                                        in  ((z, y), second a')
                 AutoArbM l s f     ->
                     AutoArbM (second <$> l)
                              s
                            $ \(z, x) -> do
                                (y, a') <- f x
                                return ((z, y), second a')

  [ 1,5,7,12 ]
  > > > streamAuto ' ( left ( sumFrom 0 ) ) [ Left 1 , Right ' a ' , Left 4 , Left 2 , Right ' b ' , Left 5 ]
  [ Left 1 , Right ' a ' , Left 5 , Left 6 , Right ' b ' , Left 12 ]
instance Monad m => ArrowChoice (Auto m) where
    left a0 = a
      where
        a = case a0 of
              AutoFunc f        ->
                  AutoFunc (left f)
              AutoFuncM f       ->
                  AutoFuncM (\x -> case x of
                               Right y -> return (Right y)
                               Left y  -> liftM Left (f y))
              AutoState gp f s  ->
                  AutoState gp (\x s' -> case x of
                                  Right y -> (Right y, s')
                                  Left y  -> first Left (f y s')
                               ) s
              AutoStateM gp f s ->
                  AutoStateM gp (\x s' -> case x of
                                   Right y -> return (Right y, s')
                                   Left y  -> liftM (first Left) (f y s')
                                ) s
              AutoArb l s f     ->
                  AutoArb (left <$> l)
                          s
                        $ \x -> case x of
                                  Right y -> (Right y, a)
                                  Left y  -> (Left *** left) (f y)
              AutoArbM l s f    ->
                  AutoArbM (left <$> l)
                           s
                         $ \x -> case x of
                                   Right y -> return (Right y, a)
                                   Left y  -> liftM (Left *** left) (f y)
    right a0 = a
      where
        a = case a0 of
              AutoFunc f ->
                  AutoFunc (fmap f)
              AutoFuncM f ->
                  AutoFuncM (sequence . fmap f)
              AutoState gp f s  ->
                  AutoState gp (\x s' -> case x of
                                  Left y  -> (Left y, s')
                                  Right y -> first Right (f y s')
                               ) s
              AutoStateM gp f s ->
                  AutoStateM gp (\x s' -> case x of
                                   Left y  -> return (Left y, s')
                                   Right y -> liftM (first Right) (f y s')
                                ) s
              AutoArb l s f     ->
                  AutoArb (right <$> l)
                          s
                        $ \x -> case x of
                                  Left y  -> (Left y, a)
                                  Right y -> (Right *** right) (f y)
              AutoArbM l s f    ->
                  AutoArbM (right <$> l)
                           s
                         $ \x -> case x of
                                   Left y  -> return (Left y, a)
                                   Right y -> liftM (Right *** right) (f y)
# INLINE right #

instance MonadFix m => ArrowLoop (Auto m) where
    loop a = case a of
                AutoFunc f        ->
                    AutoFunc (\x -> fst . fix $ \(_, d) -> f (x, d))
                AutoFuncM f       ->
                    AutoFuncM (\x -> liftM fst . mfix $ \(_, d) -> f (x, d))
                AutoState gp f s  ->
                    AutoState gp (\x s' -> first fst . fix $ \ ~((_, d), _) -> f (x, d) s') s
                AutoStateM gp f s ->
                    AutoStateM gp (\x s' -> liftM (first fst) . mfix $ \ ~((_, d), _) -> f (x, d) s') s
                AutoArb l s f     ->
                    AutoArb (loop <$> l)
                            s
                          $ \x -> (fst *** loop)
                                . fix
                                $ \ ~((_, d), _) -> f (x, d)
                AutoArbM l s f    ->
                    AutoArbM (loop <$> l)
                             s
                           $ \x -> liftM (fst *** loop)
                                 . mfix
                                 $ \ ~((_, d), _) -> f (x, d)
# INLINE loop #


instance (Monad m, Semigroup b) => Semigroup (Auto m a b) where
    (<>) = liftA2 (<>)

  | Fork the input stream and mappend the outputs .   '  ' is a constant
  stream of '  's , ignoring its input .
  > > > streamAuto ' ( mconcat [ arr ( take 3 ) ,  ( + + ) " " ] ) [ " hello","world","good","bye " ]
instance (Monad m, Monoid b) => Monoid (Auto m a b) where
    mempty  = pure mempty
    mappend = liftA2 mappend

instance (Monad m, IsString b) => IsString (Auto m a b) where
    fromString = pure . fromString

  of that ' Integer ' , so you can write ' Auto 's using numerical literals in
  > > > streamAuto ' ( sumFrom 0 ) [ 1 .. 10 ]
  [ 1,3,6,10,15,21,28,36,45,55 ]
  > > > streamAuto ' ( 4 + sumFrom 0 ) [ 1 .. 10 ]
  [ 5,7,10,14,19,25,32,40,49,59 ]
instance (Monad m, Num b) => Num (Auto m a b) where
    (+)         = liftA2 (+)
    (*)         = liftA2 (*)
    (-)         = liftA2 (-)
    negate      = fmap negate
    abs         = fmap abs
    signum      = fmap signum
    fromInteger = pure . fromInteger

  ' Rational ' , so you can write ' Auto 's using numerical literals in code ;
  see '  ' instance .
instance (Monad m, Fractional b) => Fractional (Auto m a b) where
    (/)          = liftA2 (/)
    recip        = fmap recip
    fromRational = pure . fromRational

instance (Monad m, Floating b) => Floating (Auto m a b) where
    pi      = pure pi
    exp     = fmap exp
    sqrt    = fmap sqrt
    log     = fmap log
    (**)    = liftA2 (**)
    logBase = liftA2 logBase
    sin     = fmap sin
    tan     = fmap tan
    cos     = fmap cos
    asin    = fmap asin
    atan    = fmap atan
    acos    = fmap acos
    sinh    = fmap sinh
    tanh    = fmap tanh
    cosh    = fmap cosh
    asinh   = fmap asinh
    atanh   = fmap atanh
    acosh   = fmap acosh


firstM :: Monad m => (a -> m b) -> (a, c) -> m (b, c)
firstM f ~(x, y) = liftM (, y) (f x)
# INLINE firstM #

secondM :: Monad m => (a -> m b) -> (c, a) -> m (c, b)
secondM f ~(x, y) = liftM (x,) (f y)
# INLINE secondM #
