    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Control.Arrow.Internals
    -- Copyright   :  (c) Ross Paterson 2003
    -- License     :  BSD-style (see the LICENSE file in the distribution)
    --
    -- Maintainer  :  ross@soi.city.ac.uk
    -- Stability   :  experimental
    -- Portability :  non-portable (multi-parameter type classes)
    --
    -- Manipulation of composite arrow types, beyond the basic lifting and
    -- encapsulation provided with each arrow transformer.
    --
    -- The signatures are designed to be compatible with the proposed notation
    -- for arrows, cf. <http://www.haskell.org/arrows/>.

    -- #hide
    module Control.Arrow.Internals (
    		ArrowAddState(..),
    		ArrowAddReader(..),
    		ArrowAddWriter(..),
    		ArrowAddError(..),
    		ArrowAddStream(..),
    	) where

    import Control.Arrow
    import Control.Arrow.Operations
    import Data.Stream

    -- | Adding a 'Control.Arrow.Transformer.State.StateArrow' to an
    -- arrow type, but not necessarily as the outer arrow transformer.
    --
    -- Typically a composite arrow type is built by applying a series
    -- of arrow transformer to a base arrow (usually either a function
    -- arrow or a 'Kleisli' arrow.  One can add a transformer to the
    -- top of this stack using the 'Control.Arrow.Transformer.lift'
    -- method of the 'Control.Arrow.Transformer.ArrowTransformer' class,
    -- or remove a state transformer from the top of the stack using the
    -- 'Control.Arrow.Transformer.State.runState' encapsulation operator.
    -- The methods of this class add and remove state transformers anywhere
    -- in the stack.  In the instance
    --
    -- >	instance Arrow a => ArrowAddState s (ArrowState s a) a
    --
    -- they are equivalent to 'Control.Arrow.Transformer.lift' and
    -- 'Control.Arrow.Transformer.State.runState' respectively.
    -- Instances are lifted through other transformers with
    --
    -- >	instance ArrowAddState s a a' =>
    -- >		ArrowAddState s (FooArrow a) (FooArrow a')

    class (ArrowState s a, Arrow a') => ArrowAddState s a a' | a -> a' where

    	-- | Lift a computation from an arrow to one with an added state.
    	--
    	-- Typical usage in arrow notation:
    	--
    	-- >	proc p -> ...
    	-- >		(|liftState cmd|)

    	liftState :: a' e b -> a e b

    	-- | Elimination of a state transformer from a computation,
    	-- exposing the initial and final states.
    	--
    	-- Typical usage in arrow notation:
    	--
    	-- >	proc p -> do
    	-- >		...
    	-- >		(result, final_state) <- (|elimState cmd|) init_state

    	elimState :: a e b -> a' (e,s) (b,s)

    -- | Adding a 'Control.Arrow.Transformer.Reader.ReaderArrow' to an
    -- arrow type, but not necessarily as the outer arrow transformer.
    --
    -- Typically a composite arrow type is built by applying a series
    -- of arrow transformer to a base arrow (usually either a function
    -- arrow or a 'Kleisli' arrow.  One can add a transformer to the
    -- top of this stack using the 'Control.Arrow.Transformer.lift'
    -- method of the 'Control.Arrow.Transformer.ArrowTransformer' class,
    -- or remove a state transformer from the top of the stack using the
    -- 'Control.Arrow.Transformer.Reader.runReader' encapsulation operator.
    -- The methods of this class add and remove state transformers anywhere
    -- in the stack.  In the instance
    --
    -- >	instance Arrow a => ArrowAddReader r (ArrowReader r a) a
    --
    -- they are equivalent to 'Control.Arrow.Transformer.lift' and
    -- 'Control.Arrow.Transformer.Reader.runReader' respectively.
    -- Instances are lifted through other transformers with
    --
    -- >	instance ArrowAddReader r a a' =>
    -- >		ArrowAddReader r (FooArrow a) (FooArrow a')

    class (ArrowReader r a, Arrow a') => ArrowAddReader r a a' | a -> a' where

    	-- | Lift a computation from an arrow to one with an added environment.
    	--
    	-- Typical usage in arrow notation:
    	--
    	-- >	proc p -> ...
    	-- >		(|liftReader cmd|)

    	liftReader :: a' e b -> a e b

    	-- | Elimination of a state reader from a computation,
    	-- taking a value for the state.
    	--
    	-- Typical usage in arrow notation:
    	--
    	-- >	proc p -> ...
    	-- >		(|elimReader cmd|) env

    	elimReader :: a e b -> a' (e,r) b

    -- | Adding a 'Control.Arrow.Transformer.Writer.WriterArrow' to an
    -- arrow type, but not necessarily as the outer arrow transformer.
    --
    -- Typically a composite arrow type is built by applying a series
    -- of arrow transformer to a base arrow (usually either a function
    -- arrow or a 'Kleisli' arrow.  One can add a transformer to the
    -- top of this stack using the 'Control.Arrow.Transformer.lift'
    -- method of the 'Control.Arrow.Transformer.ArrowTransformer' class,
    -- or remove a state transformer from the top of the stack using the
    -- 'Control.Arrow.Transformer.Writer.runWriter' encapsulation operator.
    -- The methods of this class add and remove state transformers anywhere
    -- in the stack.  In the instance
    --
    -- >	instance Arrow a => ArrowAddWriter w (ArrowWriter w a) a
    --
    -- they are equivalent to 'Control.Arrow.Transformer.lift' and
    -- 'Control.Arrow.Transformer.Writer.runWriter' respectively.
    -- Instances are lifted through other transformers with
    --
    -- >	instance ArrowAddWriter w a a' =>
    -- >		ArrowAddWriter w (FooArrow a) (FooArrow a')

    class (ArrowWriter w a, Arrow a') => ArrowAddWriter w a a' | a -> a' where

    	-- | Lift a computation from an arrow to one with added output.
    	--
    	-- Typical usage in arrow notation:
    	--
    	-- >	proc p -> ...
    	-- >		(|liftWriter cmd|)

    	liftWriter :: a' e b -> a e b

    	-- | Elimination of an output writer from a computation,
    	-- providing the accumulated output.
    	--
    	-- Typical usage in arrow notation:
    	--
    	-- >	proc p -> do
    	-- >		...
    	-- >		(result, output) <- (|elimWriter cmd|)

    	elimWriter :: a e b -> a' e (b,w)

    -- | Adding a 'Control.Arrow.Transformer.Error.ErrorArrow' to an
    -- arrow type, but not necessarily as the outer arrow transformer.
    --
    -- Typically a composite arrow type is built by applying a series
    -- of arrow transformer to a base arrow (usually either a function
    -- arrow or a 'Kleisli' arrow.  One can add a transformer to the
    -- top of this stack using the 'Control.Arrow.Transformer.lift'
    -- method of the 'Control.Arrow.Transformer.ArrowTransformer' class,
    -- or remove a state transformer from the top of the stack using the
    -- 'Control.Arrow.Transformer.Error.runError' encapsulation operator.
    -- The methods of this class add and remove state transformers anywhere
    -- in the stack.  In the instance
    --
    -- >	instance Arrow a => ArrowAddError ex (ArrowError ex a) a
    --
    -- they are equivalent to 'Control.Arrow.Transformer.lift' and
    -- 'Control.Arrow.Transformer.Error.runError' respectively.
    -- Instances are lifted through other transformers with
    --
    -- >	instance ArrowAddError ex a a' =>
    -- >		ArrowAddError ex (FooArrow a) (FooArrow a')
    --
    -- This could be combined with 'Control.Arrow.Transformer.Error.handle',
    -- since the resulting arrow is always the arrow of the handler.
    -- Separating them has the advantage of consistency with the other arrows,
    -- and might give more helpful type error messages.

    class (ArrowError ex a, Arrow a') => ArrowAddError ex a a' | a -> a' where

    	-- | Lift a computation from an arrow to one with error handling.
    	--
    	-- Typical usage in arrow notation:
    	--
    	-- >	proc p -> ...
    	-- >		(|liftError cmd|)

    	liftError :: a' e b -> a e b

    	-- | Elimination of errors from a computation,
    	-- by completely handling any errors.
    	--
    	-- Typical usage in arrow notation:
    	--
    	-- >	proc p -> ...
    	-- >		body `elimError` \ex -> handler

    	elimError :: a e b -> a' (e,ex) b -> a' e b

    -- | Adding a 'Control.Arrow.Transformer.Stream.StreamArrow' to an
    -- arrow type, but not necessarily as the outer arrow transformer.
    --
    -- Typically a composite arrow type is built by applying a series
    -- of arrow transformer to a base arrow (usually either a function
    -- arrow or a 'Kleisli' arrow.  One can add a transformer to the
    -- top of this stack using the 'Control.Arrow.Transformer.lift'
    -- method of the 'Control.Arrow.Transformer.ArrowTransformer' class,
    -- or remove a state transformer from the top of the stack using the
    -- 'Control.Arrow.Transformer.Stream.runStream' encapsulation operator.
    -- The methods of this class add and remove state transformers anywhere
    -- in the stack.  In the instance
    --
    -- >	instance Arrow a => ArrowAddStream (ArrowStream a) a
    --
    -- they are equivalent to 'Control.Arrow.Transformer.lift' and
    -- 'Control.Arrow.Transformer.Stream.runStream' respectively.
    -- Instances are lifted through other transformers with
    --
    -- >	instance ArrowAddStream a a' =>
    -- >		ArrowAddStream (FooArrow a) (FooArrow a')

    class (ArrowCircuit a, Arrow a') => ArrowAddStream a a' | a -> a' where

    	-- | Lift a computation from an arrow to a stream processing one.
    	--
    	-- Typical usage in arrow notation:
    	--
    	-- >	proc p -> ...
    	-- >		(|liftStream cmd|)

    	liftStream :: a' e b -> a e b

    	-- | Run a stream processor on a stream of inputs,
    	-- obtaining a stream of outputs.
    	--
    	-- Typical usage in arrow notation:
    	--
    	-- >	proc p -> do
    	-- >		...
    	-- >		ys <- (|elimStream (\x -> ...)|) xs
    	--
    	-- Here @xs@ refers to the input stream and @x@ to individual
    	-- elements of that stream.  @ys@ is bound to the output stream.

    	elimStream :: a (e,b) c -> a' (e,Stream b) (Stream c)