{-# 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
(<..>) = forall (f :: * -> *) a b c.
Apply f =>
(a -> b -> c) -> f a -> f b -> f c
liftF2 (forall a b c. (a -> b -> c) -> b -> a -> c
flip 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 forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> w a
a forall (f :: * -> *) a b. Apply f => f (a -> b) -> f a -> f b
<.> w b
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 = forall k (f :: k -> *) (a :: k). Generic1 f => Rep1 f a -> f a
to1 forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b c.
Apply f =>
(a -> b -> c) -> f a -> f b -> f c
liftF2 a -> b -> c
f (forall k (f :: k -> *) (a :: k). Generic1 f => f a -> Rep1 f a
from1 w a
wa) (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 = forall k (f :: k -> *) (a :: k). Generic1 f => Rep1 f a -> f a
to1 forall a b. (a -> b) -> a -> b
$ 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 (forall k (f :: k -> *) (a :: k). Generic1 f => f a -> Rep1 f a
from1 w a
wa) (forall k (f :: k -> *) (a :: k). Generic1 f => f a -> Rep1 f a
from1 w b
wb) (forall k (f :: k -> *) (a :: k). Generic1 f => f a -> Rep1 f a
from1 w c
wc)