```{-# OPTIONS_GHC -fno-warn-orphans #-}
-----------------------------------------------------------------------------
-- |
-- Copyright   :  (C) 2011 Edward Kmett,
--
-- Maintainer  :  Edward Kmett <ekmett@gmail.com>
-- Stability   :  provisional
-- Portability :  portable
--
----------------------------------------------------------------------------
-- * FunctorApply
, module Data.Functor.Apply
, liftW2    -- :: ComonadApply w => (a -> b -> c) -> w a -> w b -> w c
, liftW3    -- :: ComonadApply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d
) where

import Control.Applicative
import Control.Arrow
import Data.Functor.Apply
import Data.Functor.Identity
import Data.Monoid (Monoid)
import Data.Semigroup (Semigroup(..))

{- |

A strong lax symmetric semi-monoidal comonad. As such, an instance of

> extract (a <.> b) = extract a \$ extract b

This class is based on ComonadZip from \"The Essence of Dataflow Programming\"
by Tarmo Uustalu and Varmo Vene, but adapted to fit the programming style of
Control.Applicative. 'Applicative' can be seen as a similar law over and above
Apply that:

> pure (a \$ b) = pure a <.> pure b

-}

-- | Both required because Semigroup is not a superclass of Monoid
instance (Monoid m, Semigroup m) => ComonadApply ((,)m)
instance (Monoid m, Semigroup m)  => ComonadApply ((->)m)

-- | Lift a binary function into a comonad with zipping
liftW2 :: ComonadApply w => (a -> b -> c) -> w a -> w b -> w c
liftW2 = liftF2
{-# INLINE liftW2 #-}

-- | Lift a ternary function into a comonad with zipping
liftW3 :: ComonadApply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d
liftW3 = liftF3
{-# INLINE liftW3 #-}

-- | A sad little orphan
instance ComonadApply w => ArrowLoop (Cokleisli w) where
loop (Cokleisli f) = Cokleisli (fst . wfix . extend f') where
f' wa wb = f ((,) <\$> wa <.> (snd <\$> wb))
```