```{-# LANGUAGE FlexibleInstances #-}
module Control.Arrow.ApplyUtils
where
import Control.Arrow

-- | An instance that lets you work with Arrows that support ArrowApply as monads.
-- | Example:
-- |   myarrow :: ArrowApply a => a Int Int
-- |   myarrow = monadicA \$ \v -> do
-- |               let vp1 = v + 1
-- |               v' <- unmonadicA anotherIntToIntArrow vp1
-- |               return (v' * 10)
where
ArrowAsMonad \$ (x >>^ (\v -> (unApplyAsMonad (y v), ()))) >>> app
return = ArrowAsMonad . arr . const

-- | Embed a block of monadic code in an arrow.
monadicA :: ArrowApply a => (b -> ArrowAsMonad a c) -> a b c
monadicA f = arr (\v -> (unApplyAsMonad \$ f v, ())) >>> app

-- | Embed an arrow in a block of monadic code.
unmonadicA :: ArrowApply a => a b c -> b -> ArrowAsMonad a c

-- | Lift an Arrow operation.
liftA :: Arrow a => (c -> d) -> a b c -> a b d
liftA = flip (>>^)

-- | Lift an Arrow operation with two parameters
liftA2 :: ArrowApply a => (p1 -> p2 -> d) -> a b p1 -> a b p2 -> a b d
liftA2 f a1 a2 = monadicA \$ \v -> do
return (f p1 p2)

-- | Lift an Arrow operation with three parameters
liftA3 :: ArrowApply a => (p1 -> p2 -> p3 -> d) -> a b p1 -> a b p2 -> a b p3 -> a b d
liftA3 f a1 a2 a3 = monadicA \$ \v -> do
return (f p1 p2 p3)

-- | Lift an Arrow operation with four parameters
liftA4 :: ArrowApply a => (p1 -> p2 -> p3 -> p4 -> d) -> a b p1 -> a b p2 -> a b p3 -> a b p4 -> a b d
liftA4 f a1 a2 a3 a4 = monadicA \$ \v -> do
return (f p1 p2 p3 p4)

-- | Lift an Arrow operation with five parameters
liftA5 :: ArrowApply a => (p1 -> p2 -> p3 -> p4 -> p5 -> d) -> a b p1 -> a b p2 -> a b p3 -> a b p4 -> a b p5 -> a b d
liftA5 f a1 a2 a3 a4 a5 = monadicA \$ \v -> do
return (f p1 p2 p3 p4 p5)

-- | Lift an Arrow operation with six parameters
liftA6 :: ArrowApply a => (p1 -> p2 -> p3 -> p4 -> p5 -> p6 -> d) -> a b p1 -> a b p2 -> a b p3 -> a b p4 -> a b p5 -> a b p6 -> a b d
liftA6 f a1 a2 a3 a4 a5 a6 = monadicA \$ \v -> do
return (f p1 p2 p3 p4 p5 p6)

-- | Lift an Arrow operation with seven parameters
liftA7 :: ArrowApply a => (p1 -> p2 -> p3 -> p4 -> p5 -> p6 -> p7 -> d) -> a b p1 -> a b p2 -> a b p3 -> a b p4 -> a b p5 -> a b p6 -> a b p7 -> a b d
liftA7 f a1 a2 a3 a4 a5 a6 a7 = monadicA \$ \v -> do
return (f p1 p2 p3 p4 p5 p6 p7)

-- | Lift an Arrow operation with eight parameters
liftA8 :: ArrowApply a => (p1 -> p2 -> p3 -> p4 -> p5 -> p6 -> p7 -> p8 -> d) -> a b p1 -> a b p2 -> a b p3 -> a b p4 -> a b p5 -> a b p6 -> a b p7 -> a b p8 -> a b d
liftA8 f a1 a2 a3 a4 a5 a6 a7 a8 = monadicA \$ \v -> do
return (f p1 p2 p3 p4 p5 p6 p7 p8)

-- | Lift an Arrow operation with eight parameters
liftA9 :: ArrowApply a => (p1 -> p2 -> p3 -> p4 -> p5 -> p6 -> p7 -> p8 -> p9 -> d) -> a b p1 -> a b p2 -> a b p3 -> a b p4 -> a b p5 -> a b p6 -> a b p7 -> a b p8 -> a b p9 -> a b d
liftA9 f a1 a2 a3 a4 a5 a6 a7 a8 a9 = monadicA \$ \v -> do
return (f p1 p2 p3 p4 p5 p6 p7 p8 p9)

liftAM :: (ArrowApply a, Monad m) => (p1 -> c) -> a b (m p1) -> a b (m c)
liftAM f = liftA (liftM f)
liftAM2 :: (ArrowApply a, Monad m) =>
(p1 -> p2 -> c) -> a b (m p1) -> a b (m p2) -> a b (m c)
liftAM2 f = liftA2 (liftM2 f)
liftAM3 :: (ArrowApply a, Monad m) =>
(p1 -> p2 -> p3 -> c) -> a b (m p1) -> a b (m p2) -> a b (m p3) ->
a b (m c)
liftAM3 f = liftA3 (liftM3 f)
liftAM4 :: (ArrowApply a, Monad m) =>
(p1 -> p2 -> p3 -> p4 -> c) -> a b (m p1) -> a b (m p2) -> a b (m p3) ->
a b (m p4) -> a b (m c)
liftAM4 f = liftA4 (liftM4 f)
liftAM5 :: (ArrowApply a, Monad m) =>
(p1 -> p2 -> p3 -> p4 -> p5 -> c) -> a b (m p1) -> a b (m p2) ->
a b (m p3) -> a b (m p4) -> a b (m p5) -> a b (m c)
liftAM5 f = liftA5 (liftM5 f)
```