    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE Trustworthy #-}
    -----------------------------------------------------------------------------
    -- |
    -- Copyright   :  (C) 2011-2015 Edward Kmett
    -- License     :  BSD-style (see the file LICENSE)
    --
    -- Maintainer  :  Edward Kmett <ekmett@gmail.com>
    -- Stability   :  provisional
    -- Portability :  portable
    --
    ----------------------------------------------------------------------------
    module Data.Functor.Apply (
      -- * Functors
        Functor(..)
      , (<$>)     -- :: Functor f => (a -> b) -> f a -> f b
      , ( $>)     -- :: Functor f => f a -> b -> f b

      -- * Apply - a strong lax semimonoidal endofunctor

      , Apply(..)
      , (<..>)    -- :: Apply w => w a -> w (a -> b) -> w b
      , liftF3    -- :: Apply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d
      , gliftF2
      , gliftF3

      -- * Wrappers
      , WrappedApplicative(..)
      , MaybeApply(..)
      , (<.*>)
      , (<*.>)
      ) where

    import Data.Functor
    import Data.Functor.Bind.Class
    import GHC.Generics

    infixl 4 <..>

    -- | A variant of '<.>' with the arguments reversed.
    (<..>) :: Apply w => w a -> w (a -> b) -> w b
    <..> :: forall (w :: * -> *) a b. Apply w => w a -> w (a -> b) -> w b
    (<..>) = (a -> (a -> b) -> b) -> w a -> w (a -> b) -> w b
    forall a b c. (a -> b -> c) -> w a -> w b -> w c
    forall (f :: * -> *) a b c.
    Apply f =>
    (a -> b -> c) -> f a -> f b -> f c
    liftF2 (((a -> b) -> a -> b) -> a -> (a -> b) -> b
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip (a -> b) -> a -> b
    forall a. a -> a
    id)
    {-# INLINE (<..>) #-}

    -- | Lift a ternary function into a comonad with zipping
    liftF3 :: Apply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d
    liftF3 :: forall (w :: * -> *) a b c d.
    Apply w =>
    (a -> b -> c -> d) -> w a -> w b -> w c -> w d
    liftF3 a -> b -> c -> d
    f w a
    a w b
    b w c
    c = a -> b -> c -> d
    f (a -> b -> c -> d) -> w a -> w (b -> c -> d)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> w a
    a w (b -> c -> d) -> w b -> w (c -> d)
    forall a b. w (a -> b) -> w a -> w b
    forall (f :: * -> *) a b. Apply f => f (a -> b) -> f a -> f b
    <.> w b
    b w (c -> d) -> w c -> w d
    forall a b. w (a -> b) -> w a -> w b
    forall (f :: * -> *) a b. Apply f => f (a -> b) -> f a -> f b
    <.> w c
    c
    {-# INLINE liftF3 #-}

    -- | Generic 'liftF2'. Caveats:
    --
    --   1. Will not compile if @w@ is a sum type.
    --   2. Types in @w@ that do not mention the type variable must be instances of 'Semigroup'.
    --
    -- @since 5.3.8
    gliftF2 :: (Generic1 w, Apply (Rep1 w)) => (a -> b -> c) -> w a -> w b -> w c
    gliftF2 :: forall (w :: * -> *) a b c.
    (Generic1 w, Apply (Rep1 w)) =>
    (a -> b -> c) -> w a -> w b -> w c
    gliftF2 a -> b -> c
    f w a
    wa w b
    wb = Rep1 w c -> w c
    forall a. Rep1 w a -> w a
    forall k (f :: k -> *) (a :: k). Generic1 f => Rep1 f a -> f a
    to1 (Rep1 w c -> w c) -> Rep1 w c -> w c
    forall a b. (a -> b) -> a -> b
    $ (a -> b -> c) -> Rep1 w a -> Rep1 w b -> Rep1 w c
    forall a b c. (a -> b -> c) -> Rep1 w a -> Rep1 w b -> Rep1 w c
    forall (f :: * -> *) a b c.
    Apply f =>
    (a -> b -> c) -> f a -> f b -> f c
    liftF2 a -> b -> c
    f (w a -> Rep1 w a
    forall a. w a -> Rep1 w a
    forall k (f :: k -> *) (a :: k). Generic1 f => f a -> Rep1 f a
    from1 w a
    wa) (w b -> Rep1 w b
    forall a. w a -> Rep1 w a
    forall k (f :: k -> *) (a :: k). Generic1 f => f a -> Rep1 f a
    from1 w b
    wb)

    -- | Generic 'liftF3'. Caveats are the same as for 'gliftF2'.
    --
    -- @since 5.3.8
    gliftF3 :: (Generic1 w, Apply (Rep1 w)) => (a -> b -> c -> d) -> w a -> w b -> w c -> w d
    gliftF3 :: forall (w :: * -> *) a b c d.
    (Generic1 w, Apply (Rep1 w)) =>
    (a -> b -> c -> d) -> w a -> w b -> w c -> w d
    gliftF3 a -> b -> c -> d
    f w a
    wa w b
    wb w c
    wc = Rep1 w d -> w d
    forall a. Rep1 w a -> w a
    forall k (f :: k -> *) (a :: k). Generic1 f => Rep1 f a -> f a
    to1 (Rep1 w d -> w d) -> Rep1 w d -> w d
    forall a b. (a -> b) -> a -> b
    $ (a -> b -> c -> d) -> Rep1 w a -> Rep1 w b -> Rep1 w c -> Rep1 w d
    forall (w :: * -> *) a b c d.
    Apply w =>
    (a -> b -> c -> d) -> w a -> w b -> w c -> w d
    liftF3 a -> b -> c -> d
    f (w a -> Rep1 w a
    forall a. w a -> Rep1 w a
    forall k (f :: k -> *) (a :: k). Generic1 f => f a -> Rep1 f a
    from1 w a
    wa) (w b -> Rep1 w b
    forall a. w a -> Rep1 w a
    forall k (f :: k -> *) (a :: k). Generic1 f => f a -> Rep1 f a
    from1 w b
    wb) (w c -> Rep1 w c
    forall a. w a -> Rep1 w a
    forall k (f :: k -> *) (a :: k). Generic1 f => f a -> Rep1 f a
    from1 w c
    wc)