{-# LANGUAGE RankNTypes #-}
-- | This module provides very basic lens functionality, without extra dependencies.
--
-- For the documentation of the combinators see <http://hackage.haskell.org/package/lens lens> package.
-- This module uses the same vocabulary.
module Distribution.Compat.Lens (
    -- * Types
    Lens,
    Lens',
    Traversal,
    Traversal',
    -- ** LensLike
    LensLike,
    LensLike',
    -- ** rank-1 types
    Getting,
    AGetter,
    ASetter,
    ALens,
    ALens',
    -- * Getter
    view,
    use,
    getting,
    -- * Setter
    set,
    over,
    -- * Fold
    toDListOf,
    toListOf,
    toSetOf,
    -- * Lens
    cloneLens,
    aview,
    -- * Common lenses
    _1, _2,
    -- * Operators
    (&),
    (^.),
    (.~), (?~), (%~),
    (.=), (?=), (%=),
    (^#),
    (#~), (#%~),
    -- * Internal Comonads
    Pretext (..),
    -- * Cabal developer info
    -- $development
    ) where

import Prelude()
import Distribution.Compat.Prelude

import Control.Monad.State.Class (MonadState (..), gets, modify)

import qualified Distribution.Compat.DList as DList
import qualified Data.Set as Set

-------------------------------------------------------------------------------
-- Types
-------------------------------------------------------------------------------

type LensLike  f s t a b = (a -> f b) -> s -> f t
type LensLike' f s   a   = (a -> f a) -> s -> f s

type Lens      s t a b = forall f. Functor f     => LensLike f s t a b
type Traversal s t a b = forall f. Applicative f => LensLike f s t a b

type Lens'      s a = Lens s s a a
type Traversal' s a = Traversal s s a a

type Getting r s a = LensLike (Const r) s s a a

type AGetter s   a   = LensLike (Const a)     s s a a  -- this doesn't exist in 'lens'
type ASetter s t a b = LensLike Identity      s t a b
type ALens   s t a b = LensLike (Pretext a b) s t a b

type ALens' s a = ALens s s a a

-------------------------------------------------------------------------------
-- Getter
-------------------------------------------------------------------------------

view :: Getting a s a -> s ->  a
view :: forall a s. Getting a s a -> s -> a
view Getting a s a
l s
s = forall {k} a (b :: k). Const a b -> a
getConst (Getting a s a
l forall {k} a (b :: k). a -> Const a b
Const s
s)
{-# INLINE view #-}

use :: MonadState s m => Getting a s a -> m a
use :: forall s (m :: * -> *) a. MonadState s m => Getting a s a -> m a
use Getting a s a
l = forall s (m :: * -> *) a. MonadState s m => (s -> a) -> m a
gets (forall a s. Getting a s a -> s -> a
view Getting a s a
l)
{-# INLINE use #-}

-- | @since 2.4
--
-- >>> (3 :: Int) ^. getting (+2) . getting show
-- "5"
getting :: (s -> a) -> Getting r s a
getting :: forall s a r. (s -> a) -> Getting r s a
getting s -> a
k a -> Const r a
f = forall {k} a (b :: k). a -> Const a b
Const forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall {k} a (b :: k). Const a b -> a
getConst forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Const r a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. s -> a
k
{-# INLINE getting #-}

-------------------------------------------------------------------------------
-- Setter
-------------------------------------------------------------------------------

set :: ASetter s t a  b -> b -> s -> t
set :: forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter s t a b
l b
x = forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over ASetter s t a b
l (forall a b. a -> b -> a
const b
x)

over :: ASetter s t a b -> (a -> b) -> s -> t
over :: forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over ASetter s t a b
l a -> b
f s
s = forall a. Identity a -> a
runIdentity (ASetter s t a b
l (\a
x -> forall a. a -> Identity a
Identity (a -> b
f a
x)) s
s)

-------------------------------------------------------------------------------
-- Fold
-------------------------------------------------------------------------------

toDListOf :: Getting (DList.DList a) s a -> s -> DList.DList a
toDListOf :: forall a s. Getting (DList a) s a -> s -> DList a
toDListOf Getting (DList a) s a
l s
s = forall {k} a (b :: k). Const a b -> a
getConst (Getting (DList a) s a
l (\a
x -> forall {k} a (b :: k). a -> Const a b
Const (forall a. a -> DList a
DList.singleton a
x)) s
s)

toListOf :: Getting (DList.DList a) s a -> s -> [a]
toListOf :: forall a s. Getting (DList a) s a -> s -> [a]
toListOf Getting (DList a) s a
l = forall a. DList a -> [a]
DList.runDList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a s. Getting (DList a) s a -> s -> DList a
toDListOf Getting (DList a) s a
l

toSetOf  :: Getting (Set.Set a) s a -> s -> Set.Set a
toSetOf :: forall a s. Getting (Set a) s a -> s -> Set a
toSetOf Getting (Set a) s a
l s
s = forall {k} a (b :: k). Const a b -> a
getConst (Getting (Set a) s a
l (\a
x -> forall {k} a (b :: k). a -> Const a b
Const (forall a. a -> Set a
Set.singleton a
x)) s
s)

-------------------------------------------------------------------------------
-- Lens
-------------------------------------------------------------------------------

aview :: ALens s t a b -> s -> a
aview :: forall s t a b. ALens s t a b -> s -> a
aview ALens s t a b
l = forall a b t. Pretext a b t -> a
pretextPos  forall b c a. (b -> c) -> (a -> b) -> a -> c
. ALens s t a b
l forall a b. a -> Pretext a b b
pretextSell
{-# INLINE aview #-}

{-
lens :: (s -> a) -> (s -> a -> s) -> Lens' s a
lens sa sbt afb s = sbt s <$> afb (sa s)
-}

-------------------------------------------------------------------------------
-- Common
-------------------------------------------------------------------------------

_1 ::  Lens (a, c) (b, c) a b
_1 :: forall a c b. Lens (a, c) (b, c) a b
_1 a -> f b
f (a
a, c
c) = forall a b c. (a -> b -> c) -> b -> a -> c
flip (,) c
c forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> f b
f a
a

_2 ::  Lens (c, a) (c, b) a b
_2 :: forall c a b. Lens (c, a) (c, b) a b
_2 a -> f b
f (c
c, a
a) = (,) c
c forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> f b
f a
a

-------------------------------------------------------------------------------
-- Operators
-------------------------------------------------------------------------------

-- | '&' is a reverse application operator
(&) :: a -> (a -> b) -> b
& :: forall a b. a -> (a -> b) -> b
(&) = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a b. (a -> b) -> a -> b
($)
{-# INLINE (&) #-}
infixl 1 &

infixl 8 ^., ^#
infixr 4 .~, %~, ?~
infixr 4 #~, #%~
infixr 4 .=, %=, ?=

(^.) :: s -> Getting a s a -> a
s
s ^. :: forall s a. s -> Getting a s a -> a
^. Getting a s a
l = forall {k} a (b :: k). Const a b -> a
getConst (Getting a s a
l forall {k} a (b :: k). a -> Const a b
Const s
s)
{-# INLINE (^.) #-}

(.~) :: ASetter s t a b -> b -> s -> t
.~ :: forall s t a b. ASetter s t a b -> b -> s -> t
(.~) = forall s t a b. ASetter s t a b -> b -> s -> t
set
{-# INLINE (.~) #-}

(?~) :: ASetter s t a (Maybe b) -> b -> s -> t
ASetter s t a (Maybe b)
l ?~ :: forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ b
b = forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter s t a (Maybe b)
l (forall a. a -> Maybe a
Just b
b)
{-# INLINE (?~) #-}

(%~) :: ASetter s t a b -> (a -> b) -> s -> t
%~ :: forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
(%~) = forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over
{-# INLINE (%~) #-}

(.=) :: MonadState s m => ASetter s s a b -> b -> m ()
ASetter s s a b
l .= :: forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> b -> m ()
.= b
b = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (ASetter s s a b
l forall s t a b. ASetter s t a b -> b -> s -> t
.~ b
b)
{-# INLINE (.=) #-}

(?=) :: MonadState s m => ASetter s s a (Maybe b) -> b -> m ()
ASetter s s a (Maybe b)
l ?= :: forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a (Maybe b) -> b -> m ()
?= b
b = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (ASetter s s a (Maybe b)
l forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ b
b)
{-# INLINE (?=) #-}

(%=) :: MonadState s m => ASetter s s a b -> (a -> b) -> m ()
ASetter s s a b
l %= :: forall s (m :: * -> *) a b.
MonadState s m =>
ASetter s s a b -> (a -> b) -> m ()
%= a -> b
f = forall s (m :: * -> *). MonadState s m => (s -> s) -> m ()
modify (ASetter s s a b
l forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ a -> b
f)
{-# INLINE (%=) #-}

(^#) :: s -> ALens s t a b -> a
s
s ^# :: forall s t a b. s -> ALens s t a b -> a
^# ALens s t a b
l = forall s t a b. ALens s t a b -> s -> a
aview ALens s t a b
l s
s

(#~) :: ALens s t a b -> b -> s -> t
#~ :: forall s t a b. ALens s t a b -> b -> s -> t
(#~) ALens s t a b
l b
b s
s = forall b a t. b -> Pretext a b t -> t
pretextPeek b
b (ALens s t a b
l forall a b. a -> Pretext a b b
pretextSell s
s)
{-# INLINE (#~) #-}

(#%~) :: ALens s t a b -> (a -> b) -> s -> t
#%~ :: forall s t a b. ALens s t a b -> (a -> b) -> s -> t
(#%~) ALens s t a b
l a -> b
f s
s = forall a b t. (a -> b) -> Pretext a b t -> t
pretextPeeks a -> b
f (ALens s t a b
l forall a b. a -> Pretext a b b
pretextSell s
s)
{-# INLINE (#%~) #-}

pretextSell :: a -> Pretext a b b
pretextSell :: forall a b. a -> Pretext a b b
pretextSell a
a = forall a b t.
(forall (f :: * -> *). Functor f => (a -> f b) -> f t)
-> Pretext a b t
Pretext (\a -> f b
afb -> a -> f b
afb a
a)
{-# INLINE pretextSell #-}

pretextPeeks :: (a -> b) -> Pretext a b t -> t
pretextPeeks :: forall a b t. (a -> b) -> Pretext a b t -> t
pretextPeeks a -> b
f (Pretext forall (f :: * -> *). Functor f => (a -> f b) -> f t
m) = forall a. Identity a -> a
runIdentity forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *). Functor f => (a -> f b) -> f t
m (\a
x -> forall a. a -> Identity a
Identity (a -> b
f a
x))
{-# INLINE pretextPeeks #-}

pretextPeek :: b -> Pretext a b t -> t
pretextPeek :: forall b a t. b -> Pretext a b t -> t
pretextPeek b
b (Pretext forall (f :: * -> *). Functor f => (a -> f b) -> f t
m) = forall a. Identity a -> a
runIdentity forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *). Functor f => (a -> f b) -> f t
m (\a
_ -> forall a. a -> Identity a
Identity b
b)
{-# INLINE pretextPeek #-}

pretextPos :: Pretext a b t -> a
pretextPos :: forall a b t. Pretext a b t -> a
pretextPos (Pretext forall (f :: * -> *). Functor f => (a -> f b) -> f t
m) = forall {k} a (b :: k). Const a b -> a
getConst (forall (f :: * -> *). Functor f => (a -> f b) -> f t
m forall {k} a (b :: k). a -> Const a b
Const)
{-# INLINE pretextPos #-}

cloneLens :: Functor f => ALens s t a b -> LensLike f s t a b
cloneLens :: forall (f :: * -> *) s t a b.
Functor f =>
ALens s t a b -> LensLike f s t a b
cloneLens ALens s t a b
l a -> f b
f s
s = forall a b t.
Pretext a b t
-> forall (f :: * -> *). Functor f => (a -> f b) -> f t
runPretext (ALens s t a b
l forall a b. a -> Pretext a b b
pretextSell s
s) a -> f b
f
{-# INLINE cloneLens #-}

-------------------------------------------------------------------------------
-- Comonads
-------------------------------------------------------------------------------

-- | @lens@ variant is also parametrised by profunctor.
data Pretext a b t = Pretext { forall a b t.
Pretext a b t
-> forall (f :: * -> *). Functor f => (a -> f b) -> f t
runPretext :: forall f. Functor f => (a -> f b) -> f t }

instance Functor (Pretext a b) where
    fmap :: forall a b. (a -> b) -> Pretext a b a -> Pretext a b b
fmap a -> b
f (Pretext forall (f :: * -> *). Functor f => (a -> f b) -> f a
pretext) = forall a b t.
(forall (f :: * -> *). Functor f => (a -> f b) -> f t)
-> Pretext a b t
Pretext (\a -> f b
afb -> forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f (forall (f :: * -> *). Functor f => (a -> f b) -> f a
pretext a -> f b
afb))

-------------------------------------------------------------------------------
-- Documentation
-------------------------------------------------------------------------------

-- $development
--
-- We cannot depend on @template-haskell@, because Cabal is a boot library.
-- This fact makes defining optics a manual task. Here is a small recipe to
-- make the process less tedious.
--
-- First start a repl
--
-- > cabal new-repl Cabal:hackage-tests
--
-- Because @--extra-package@ isn't yet implemented, we use a test-suite
-- with @generics-sop@ dependency.
--
-- In the repl, we load a helper script:
--
-- > :l ../generics-sop-lens.hs
--
-- Now we are set up to derive lenses!
--
-- > :m +Distribution.Types.SourceRepo
-- > putStr $ genericLenses (Proxy :: Proxy SourceRepo)
--
-- @
-- repoKind :: Lens' SourceRepo RepoKind
-- repoKind f s = fmap (\\x -> s { T.repoKind = x }) (f (T.repoKind s))
-- \{-# INLINE repoKind #-\}
-- ...
-- @
--
-- /Note:/ You may need to adjust type-aliases, e.g. `String` to `FilePath`.