-- |
-- Description: Public interface
--
-- = Normalizing applicative functors
--
-- Normalize applicative expressions
-- by simplifying intermediate 'pure' and @('<$>')@ and reassociating @('<*>')@.
--
-- This works by transforming the underlying applicative functor into one whose
-- operations ('pure', @('<$>')@, @('<*>')@) reassociate themselves by inlining
-- and beta-reduction.
--
-- It relies entirely on GHC's simplifier. No rewrite rules, no Template
-- Haskell, no plugins.
--
-- == Example
--
-- In the following traversal, one of the actions is @pure b@, which
-- can be simplified in principle, but only assuming the applicative functor
-- laws. As far as GHC is concerned, 'pure', @('<$>')@, and @('<*>')@ are
-- completely opaque because @f@ is abstract, so it cannot simplify this
-- expression.
--
-- @
-- data Example a = Example a Bool [a] (Example a)
--
-- traverseE :: Applicative f => (a -> f b) -> Example a -> f (Example b)
-- traverseE go (Example a b c d) =
--   Example
--     \<$\> go a
--     \<*\> pure b
--     \<*\> traverse go c
--     \<*\> traverseE go d
--   -- 1 \<$\>, 3 \<*\>
-- @
--
-- Using this library, we can compose actions in a specialized applicative
-- functor @'Aps' f@, keeping the code in roughly the same structure.
-- In the following snippet, identifiers exported by the library are highlighted.
--
-- @
-- traverseE :: Applicative f => (a -> f b) -> Example a -> f (Example b)
-- traverseE go (Example a b c d) =
--   Example
--     '<$>^' go a
--     \<*\>  pure b
--     '<*>^' traverse go c
--     '<*>^' traverseE go d
--     '&' 'lowerAps'
--   -- 1 \<$\>, 3 \<*\>
-- @
--
-- GHC simplifies that traversal to the following, using only two
-- combinators in total.
--
-- @
-- traverseE :: Applicative f => (a -> f b) -> Example a -> f (Example b)
-- traverseE go (Example a b c d) =
--   liftA2 (\\a' -> Example a' b)
--     (go a)
--     (traverse go c)
--     \<*\> traverseE go d
--   -- 1 liftA2, 1 \<*\>
-- @
--
-- The following example with a tree-shaped structure also reduces to the same
-- list-shaped expression above.
--
-- @
-- traverseE :: Applicative f => (a -> f b) -> Example a -> f (Example b)
-- traverseE go (Example a b c d) =
--   (\\((a', b'), (c', d')) -> Example a' b' c' d')
--     \<$\> ((,) \<$\> ((,) '<$>^' go a
--                       \<*\>  pure b)
--              \<*\> ((,) '<$>^' traverse go c
--                       '<*>^' traverseE go d))
--     '&' 'lowerAps'
--   -- 4 \<$\>, 3 \<*\>
-- @
--
-- Such structure occurs when using an intermediate definition (which itself
-- uses the applicative operators) as the right operand of @('<$>')@ or
-- @('<*>')@.
-- This could also be found in a naive generic implementation of 'traverse'
-- using "GHC.Generics".
--
-- == Usage
--
-- The main idea is to compose applicative actions not directly in your applicative
-- functor @f@, but in a transformed one @'Aps' f@.
--
-- - Send actions from @f@ into @'Aps' f@ using 'liftAps'.
-- - 'pure' actions lift themselves already:
--   @pure x@ can be specialized to both @f@ and @Aps f@.
-- - Compose actions in @'Aps' f@ using applicative combinators such as
--   @('<$>')@, @('<*>')@, and 'Control.Applicative.liftA2'.
-- - Move back from @'Aps' f@ to @f@ using 'lowerAps'.
--
-- The shorthands @('<$>^')@ and @('<*>^')@ can be used instead of
-- @('<$>')@ and @('<*>')@ with a neighboring 'liftAps'.
--
-- Definitions in @'Aps' f@ should not be recursive,
-- since this relies on inlining,
-- and recursive functions are not inlined by GHC.

module ApNormalize
  ( -- * Interface
    Aps
  , (<$>^)
  , (<*>^)
  , liftAps
  , lowerAps

    -- * Reexported from @Data.Function@
    --
    -- | For convenience, to append @... '&' 'lowerAps'@ to the
    -- end of an applicative expression.
  , (&)
  ) where

import Data.Function ((&))
import ApNormalize.Aps