2013/2/11 Ertugrul Söylemez <es@ertes.de>
... 
## Applicative

One of the main bottlenecks of arrows is the heavy tuple handling, but
most (if not all) arrows form a family of applicative functors.  I
noticed a huge speedup by moving from arrow style to applicative style
where possible:

    liftA2 (+) (lmap f c) (fmap g d)

is often much faster than:

    arr (uncurry (+)) . (c . arr f &&& arr g . d)

Besides being more readable it sometimes improved the performance of my
code by an order of magnitude.  So perhaps check to see if the category
forms an applicative functor.  If it does, you can get along without
Arrow entirely.

I've been reading Idioms are oblivious, arrows are meticulous, monads are promiscuous recently, and if I understand it correctly, an arrow forms an applicative functor if it's possible to define a delaying operation on it, which separates the arrow's effect from its computation:

    class Arrow a => ArrowDelay a where
        delay :: a b c -> a () (b -> c)

    -- Definable for any arrow:
    force :: Arrow a => a () (b -> c) -> a b c
    force af = (,) () ^>> first af >>^ uncurry ($)


and satisfying `force . delay = id = delay . force`.
While the implementation of Applicative can be defined without actually using `delay`:

    newtype ArrowApp a b c = ArrowApp (a b c)

    instance Arrow a => Functor (ArrowApp a b) where
        fmap f (ArrowApp a) = ArrowApp (a >>^ f)
    instance ArrowDelay a => Applicative (ArrowApp a b) where
        pure x =
            ArrowApp $ arr (const x)
        (ArrowApp af) <*> (ArrowApp ax) =
            ArrowApp $ (af &&& ax) >>^ uncurry ($)

I believe it only satisfies the laws only if the arrow satisfies delay/force laws.

Perhaps it would be convenient to have ArrowDelay and the corresponding conversions included in the library so that defining and using Applicative instances for arrows would become more straightforward.

  Best regards,
  Petr Pudlak