    {- |
    This module defines the @Accessor@ type.
    It should be imported with qualification.
    -}
    module Data.Accessor.Basic (
       T, fromSetGet, fromLens, fromWrapper,
       self, null, result,
       set, (^=), compose,
       get, (^.),
       modify, (^:),
       (.>), (<.),
       ($%),
       merge,
       ) where

    import qualified Data.Accessor.Private as A
    import Data.Accessor.Private (T(..), )
    import Prelude hiding (null)

    -- * Define and construct accessors

    fromSetGet :: (a -> r -> r) -> (r -> a) -> T r a
    fromSetGet :: forall a r. (a -> r -> r) -> (r -> a) -> T r a
    fromSetGet a -> r -> r
    setF r -> a
    getF =
       (r -> (a, a -> r)) -> T r a
    forall r a. (r -> (a, a -> r)) -> T r a
    Cons ((r -> (a, a -> r)) -> T r a) -> (r -> (a, a -> r)) -> T r a
    forall a b. (a -> b) -> a -> b
    $ \r
    r -> (r -> a
    getF r
    r, (a -> r -> r) -> r -> a -> r
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip a -> r -> r
    setF r
    r)

    fromLens :: (r -> (a, a -> r)) -> T r a
    fromLens :: forall r a. (r -> (a, a -> r)) -> T r a
    fromLens = (r -> (a, a -> r)) -> T r a
    forall r a. (r -> (a, a -> r)) -> T r a
    Cons

    {- |
    If an object is wrapped in a @newtype@,
    you can generate an @Accessor@ to the unwrapped data
    by providing a wrapper and an unwrapper function.
    The set function is simpler in this case,
    since no existing data must be kept.
    Since the information content of the wrapped and unwrapped data is equivalent,
    you can swap wrapper and unwrapper.
    This way you can construct an @Accessor@
    that treats a record field containing an unwrapped object
    like a field containing a wrapped object.

    > newtype A = A {unA :: Int}
    >
    > access :: Accessor.T A Int
    > access = fromWrapper A unA

    We could also have called this function @fromBijection@,
    since it must hold @wrap . unwrap = id@ and @unwrap . wrap = id@.
    -}
    fromWrapper :: (b -> a) -> (a -> b) -> T a b
    fromWrapper :: forall b a. (b -> a) -> (a -> b) -> T a b
    fromWrapper b -> a
    wrap a -> b
    unwrap =
       (b -> a -> a) -> (a -> b) -> T a b
    forall a r. (a -> r -> r) -> (r -> a) -> T r a
    fromSetGet (a -> a -> a
    forall a b. a -> b -> a
    const (a -> a -> a) -> (b -> a) -> b -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . b -> a
    wrap) a -> b
    unwrap

    {- test whether the example can be compiled
    newtype A = A {unA :: Int}

    access :: T A Int
    access = fromWrapper A unA
    -}

    -- Simple accessors

    {- |
    Access the record itself
    -}
    self :: T r r
    self :: forall r. T r r
    self = T r r
    forall r. T r r
    A.self
    -- self = fromSetGet const id

    {- |
    Access a (non-existing) element of type @()@
    -}
    null :: T r ()
    null :: forall r. T r ()
    null = (() -> r -> r) -> (r -> ()) -> T r ()
    forall a r. (a -> r -> r) -> (r -> a) -> T r a
    fromSetGet ((r -> () -> r) -> () -> r -> r
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip r -> () -> r
    forall a b. a -> b -> a
    const) (() -> r -> ()
    forall a b. a -> b -> a
    const ())

    {- |
    @result a@ accesses the value of a function for argument @a@.
    It is not very efficient to build a function
    from setting all of its values using this accessor,
    since every access to a function adds another @if-then-else@.

    Also see semantic editor combinators,
    that allow to modify all function values of a function at once.
    Cf. <http://conal.net/blog/posts/semantic-editor-combinators/>
    -}
    result :: Eq a => a -> T (a -> b) b
    result :: forall a b. Eq a => a -> T (a -> b) b
    result a
    ai =
       (b -> (a -> b) -> a -> b) -> ((a -> b) -> b) -> T (a -> b) b
    forall a r. (a -> r -> r) -> (r -> a) -> T r a
    fromSetGet (\b
    r a -> b
    f a
    a -> if a
    aa -> a -> Bool
    forall a. Eq a => a -> a -> Bool
    ==a
    ai then b
    r else a -> b
    f a
    a) ((a -> b) -> a -> b
    forall a b. (a -> b) -> a -> b
    $ a
    ai)

    -- * Apply accessors, similar to State methods

    {- | Set the value of a field. -}
    set :: T r a -> a -> r -> r
    set :: forall r a. T r a -> a -> r -> r
    set T r a
    f a
    a r
    r = (a, a -> r) -> a -> r
    forall a b. (a, b) -> b
    snd (T r a -> r -> (a, a -> r)
    forall r a. T r a -> r -> (a, a -> r)
    decons T r a
    f r
    r) a
    a

    infixr 5 ^=, ^:

    {- |
    'set' as infix operator.
    This lets us write @first ^= 2+3 $ second ^= 5+7 $ record@.
    -}
    (^=) :: T r a -> a -> (r -> r)
    ^= :: forall r a. T r a -> a -> r -> r
    (^=) = T r a -> a -> r -> r
    forall r a. T r a -> a -> r -> r
    set

    {-
    {- | Set many fields at once.

    This function could also be used for initialisation of record,
    if record value with undefined fields is provided.

    Drawback:
    Since all types in a list must have the same type,
    you can set only values of the same type.
    -}
    setMany :: [r -> (a, r)] -> r -> r
    setMany = flip (foldl (\x f -> snd (f x)))
    -}

    {- |
    This is a general function,
    but it is especially useful for setting many values of different type at once.
    -}
    compose :: [r -> r] -> r -> r
    compose :: forall r. [r -> r] -> r -> r
    compose = (r -> [r -> r] -> r) -> [r -> r] -> r -> r
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip ((r -> (r -> r) -> r) -> r -> [r -> r] -> r
    forall b a. (b -> a -> b) -> b -> [a] -> b
    forall (t :: * -> *) b a.
    Foldable t =>
    (b -> a -> b) -> b -> t a -> b
    foldl (((r -> r) -> r -> r) -> r -> (r -> r) -> r
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip (r -> r) -> r -> r
    forall a. a -> a
    id))

    {- | Get the value of a field. -}
    get :: T r a -> r -> a
    get :: forall r a. T r a -> r -> a
    get T r a
    f = (a, a -> r) -> a
    forall a b. (a, b) -> a
    fst ((a, a -> r) -> a) -> (r -> (a, a -> r)) -> r -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . T r a -> r -> (a, a -> r)
    forall r a. T r a -> r -> (a, a -> r)
    decons T r a
    f

    infixl 8 ^.

    {- |
    'get' as infix operator.
    This lets us write @record^.field^.subfield@.
    This imitates Modula II syntax.
    -}
    (^.) :: r -> T r a -> a
    ^. :: forall r a. r -> T r a -> a
    (^.) = (T r a -> r -> a) -> r -> T r a -> a
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip T r a -> r -> a
    forall r a. T r a -> r -> a
    get

    {- | Transform the value of a field by a function. -}
    modify :: T r a -> (a -> a) -> (r -> r)
    modify :: forall r a. T r a -> (a -> a) -> r -> r
    modify T r a
    f a -> a
    g r
    rOld =
       let (a
    a,a -> r
    rSetA) = T r a -> r -> (a, a -> r)
    forall r a. T r a -> r -> (a, a -> r)
    decons T r a
    f r
    rOld
       in  a -> r
    rSetA (a -> a
    g a
    a)

    {- |
    'modify' as infix operator.
    This lets us write
    @field^:subfield^:(2*) $ record@,
    @record$%field^:subfield^:(2*)@
    or @record$%field^:subfield^:(const 1)@.
    -}
    (^:) :: T r a -> (a -> a) -> (r -> r)
    ^: :: forall r a. T r a -> (a -> a) -> r -> r
    (^:) = T r a -> (a -> a) -> r -> r
    forall r a. T r a -> (a -> a) -> r -> r
    modify

    infixl 0 $%

    {- |
    Flipped version of '($)'.
    -}
    -- ToDo: could be re-exported from utility-ht
    ($%) :: a -> (a -> b) -> b
    $% :: forall a b. a -> (a -> b) -> b
    ($%) = ((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 b. (a -> b) -> a -> b
    ($)

    -- * Accessor combinators

    infixl 9 .>

    {- |
    Accessor composition:
    Combine an accessor with an accessor to a sub-field.
    Speak \"stack\".
    -}
    (.>) :: T a b -> T b c -> T a c
    .> :: forall a b c. T a b -> T b c -> T a c
    (.>) = T a b -> T b c -> T a c
    forall a b c. T a b -> T b c -> T a c
    A.compose

    {-
    This could be used for a Category instance of T.
    -}

    infixr 9 <.

    {- |
    Accessor composition the other direction.

    > (<.) = flip (.>)

    You may also use the @(.)@ operator from Category class.
    -}
    (<.) :: T b c -> T a b -> T a c
    <. :: forall b c a. T b c -> T a b -> T a c
    (<.) = (T a b -> T b c -> T a c) -> T b c -> T a b -> T a c
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip T a b -> T b c -> T a c
    forall a b c. T a b -> T b c -> T a c
    A.compose

    {- |
    Merge the accessors to two independent fields.

    Independency means, it must hold:

    > set (merge accA accB) (a,b) = set (merge accB accA) (b,a)

    You may construct smart accessors
    by composing a merged accessor with a @fromWrapper@ accessor.

    This is a special case of the more general @Point@ concept
    in the package @fclabels@.
    -}
    merge :: T a b -> T a c -> T a (b,c)
    merge :: forall a b c. T a b -> T a c -> T a (b, c)
    merge T a b
    accB T a c
    accC =
       ((b, c) -> a -> a) -> (a -> (b, c)) -> T a (b, c)
    forall a r. (a -> r -> r) -> (r -> a) -> T r a
    fromSetGet
          (\(b
    b,c
    c) -> T a b -> b -> a -> a
    forall r a. T r a -> a -> r -> r
    set T a b
    accB b
    b (a -> a) -> (a -> a) -> a -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . T a c -> c -> a -> a
    forall r a. T r a -> a -> r -> r
    set T a c
    accC c
    c)
          (\a
    a -> (T a b -> a -> b
    forall r a. T r a -> r -> a
    get T a b
    accB a
    a, T a c -> a -> c
    forall r a. T r a -> r -> a
    get T a c
    accC a
    a))