{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeOperators #-}

module Control.Effect.Optics.Indexed
  ( -- * Indexed reader operations
    iview,
    iviews,
    ilocally,

    -- * Indexed state operations
    iuse,
    iuses,
  )
where

import Control.Effect.Reader as Reader
import Control.Effect.State as State
import Optics.Core hiding (iview, iviews)
import qualified Optics.Core as Optics

-- | View the index and value of an indexed getter into the current environment as a pair.
iview :: (Is k A_Getter, is `HasSingleIndex` i, Has (Reader.Reader r) sig m) => Optic' k is r a -> m (i, a)
iview :: forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (r :: OpticKind)
       (sig :: (OpticKind -> OpticKind) -> OpticKind -> OpticKind)
       (m :: OpticKind -> OpticKind) (a :: OpticKind).
(Is k A_Getter, HasSingleIndex is i, Has (Reader r) sig m) =>
Optic' k is r a -> m (i, a)
iview Optic' k is r a
l = (r -> (i, a)) -> m (i, a)
forall (r :: OpticKind)
       (sig :: (OpticKind -> OpticKind) -> OpticKind -> OpticKind)
       (m :: OpticKind -> OpticKind) (a :: OpticKind).
Has (Reader r) sig m =>
(r -> a) -> m a
Reader.asks (Optic' k is r a -> r -> (i, a)
forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (s :: OpticKind) (a :: OpticKind).
(Is k A_Getter, HasSingleIndex is i) =>
Optic' k is s a -> s -> (i, a)
Optics.iview Optic' k is r a
l)

-- | View the index and value of an indexed getter into the current environment and pass them to the provided function.
iviews :: (Is k A_Getter, is `HasSingleIndex` i, Has (Reader.Reader r) sig m) => Optic' k is r a -> (i -> a -> m b) -> m b
iviews :: forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (r :: OpticKind)
       (sig :: (OpticKind -> OpticKind) -> OpticKind -> OpticKind)
       (m :: OpticKind -> OpticKind) (a :: OpticKind) (b :: OpticKind).
(Is k A_Getter, HasSingleIndex is i, Has (Reader r) sig m) =>
Optic' k is r a -> (i -> a -> m b) -> m b
iviews Optic' k is r a
l i -> a -> m b
f = m r
forall (r :: OpticKind)
       (sig :: (OpticKind -> OpticKind) -> OpticKind -> OpticKind)
       (m :: OpticKind -> OpticKind).
Has (Reader r) sig m =>
m r
Reader.ask m r -> (r -> m b) -> m b
forall (m :: OpticKind -> OpticKind) (a :: OpticKind)
       (b :: OpticKind).
Monad m =>
m a -> (a -> m b) -> m b
>>= Optic' k is r a -> (i -> a -> m b) -> r -> m b
forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (s :: OpticKind) (a :: OpticKind) (r :: OpticKind).
(Is k A_Getter, HasSingleIndex is i) =>
Optic' k is s a -> (i -> a -> r) -> s -> r
Optics.iviews Optic' k is r a
l i -> a -> m b
f

-- | Given a monadic argument, evaluate it in a context modified by applying
-- the provided function to the index and target of the provided indexed 'Setter', 'Lens', or 'Traversal'.
ilocally :: (Has (Reader s) sig m, is `HasSingleIndex` i, Is k A_Setter) => Optic k is s s a1 b -> (i -> a1 -> b) -> m a2 -> m a2
ilocally :: forall (s :: OpticKind)
       (sig :: (OpticKind -> OpticKind) -> OpticKind -> OpticKind)
       (m :: OpticKind -> OpticKind) (is :: IxList) (i :: OpticKind)
       (k :: OpticKind) (a1 :: OpticKind) (b :: OpticKind)
       (a2 :: OpticKind).
(Has (Reader s) sig m, HasSingleIndex is i, Is k A_Setter) =>
Optic k is s s a1 b -> (i -> a1 -> b) -> m a2 -> m a2
ilocally Optic k is s s a1 b
l i -> a1 -> b
f = (s -> s) -> m a2 -> m a2
forall (r :: OpticKind)
       (sig :: (OpticKind -> OpticKind) -> OpticKind -> OpticKind)
       (m :: OpticKind -> OpticKind) (a :: OpticKind).
Has (Reader r) sig m =>
(r -> r) -> m a -> m a
Reader.local (Optic k is s s a1 b -> (i -> a1 -> b) -> s -> s
forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (s :: OpticKind) (t :: OpticKind) (a :: OpticKind)
       (b :: OpticKind).
(Is k A_Setter, HasSingleIndex is i) =>
Optic k is s t a b -> (i -> a -> b) -> s -> t
iover Optic k is s s a1 b
l i -> a1 -> b
f)

-- | Extract the index and target of an indexed getter in the current state as a pair.
iuse :: (Is k A_Getter, is `HasSingleIndex` i, Has (State s) sig m) => Optic' k is s a -> m (i, a)
iuse :: forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (s :: OpticKind)
       (sig :: (OpticKind -> OpticKind) -> OpticKind -> OpticKind)
       (m :: OpticKind -> OpticKind) (a :: OpticKind).
(Is k A_Getter, HasSingleIndex is i, Has (State s) sig m) =>
Optic' k is s a -> m (i, a)
iuse Optic' k is s a
l = (s -> (i, a)) -> m (i, a)
forall (s :: OpticKind)
       (sig :: (OpticKind -> OpticKind) -> OpticKind -> OpticKind)
       (m :: OpticKind -> OpticKind) (a :: OpticKind).
Has (State s) sig m =>
(s -> a) -> m a
State.gets (Optic' k is s a -> s -> (i, a)
forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (s :: OpticKind) (a :: OpticKind).
(Is k A_Getter, HasSingleIndex is i) =>
Optic' k is s a -> s -> (i, a)
Optics.iview Optic' k is s a
l)

-- | Extract the index and target of an indexed getter in the current state and pass them to the provided function.
iuses :: (Is k A_Getter, is `HasSingleIndex` i, Has (State s) sig m) => Optic' k is s a -> (i -> a -> m b) -> m b
iuses :: forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (s :: OpticKind)
       (sig :: (OpticKind -> OpticKind) -> OpticKind -> OpticKind)
       (m :: OpticKind -> OpticKind) (a :: OpticKind) (b :: OpticKind).
(Is k A_Getter, HasSingleIndex is i, Has (State s) sig m) =>
Optic' k is s a -> (i -> a -> m b) -> m b
iuses Optic' k is s a
l i -> a -> m b
r = m s
forall (s :: OpticKind)
       (sig :: (OpticKind -> OpticKind) -> OpticKind -> OpticKind)
       (m :: OpticKind -> OpticKind).
Has (State s) sig m =>
m s
State.get m s -> (s -> m b) -> m b
forall (m :: OpticKind -> OpticKind) (a :: OpticKind)
       (b :: OpticKind).
Monad m =>
m a -> (a -> m b) -> m b
>>= Optic' k is s a -> (i -> a -> m b) -> s -> m b
forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (s :: OpticKind) (a :: OpticKind) (r :: OpticKind).
(Is k A_Getter, HasSingleIndex is i) =>
Optic' k is s a -> (i -> a -> r) -> s -> r
Optics.iviews Optic' k is s a
l i -> a -> m b
r