-- Copyright 2021 Google LLC
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

-- | An extension of 'Traversable10' that provides access to some 'Index10'.

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

module Data.Ten.Traversable.WithIndex
         ( Index10, Traversable10WithIndex(..), itraverse10
         , traverse10C
         ) where

import GHC.Generics ((:.:)(..))

import Data.Ten.Entails (Entails(..), byEntailment)
import Data.Ten.Foldable.WithIndex (Foldable10WithIndex(..))
import Data.Ten.Functor.WithIndex (Index10, Functor10WithIndex(..))
import Data.Ten.Traversable (Traversable10(..))

-- | An extension of 'Traversable10' that provides access to some 'Index10'.
class (Functor10WithIndex f, Foldable10WithIndex f, Traversable10 f)
   => Traversable10WithIndex f where
  imapTraverse10
    :: Applicative g
    => (f n -> r)
    -> (forall a. Index10 f a -> m a -> g (n a))
    -> f m -> g r

instance (Traversable g, Traversable10WithIndex f)
      => Traversable10WithIndex (g :.: f) where
  imapTraverse10 :: ((:.:) g f n -> r)
-> (forall (a :: k). Index10 (g :.: f) a -> m a -> g (n a))
-> (:.:) g f m
-> g r
imapTraverse10 (:.:) g f n -> r
r forall (a :: k). Index10 (g :.: f) a -> m a -> g (n a)
f (Comp1 g (f m)
gfm) =
    (:.:) g f n -> r
r ((:.:) g f n -> r) -> (g (f n) -> (:.:) g f n) -> g (f n) -> r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. g (f n) -> (:.:) g f n
forall k2 k1 (f :: k2 -> *) (g :: k1 -> k2) (p :: k1).
f (g p) -> (:.:) f g p
Comp1 (g (f n) -> r) -> g (g (f n)) -> g r
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (f m -> g (f n)) -> g (f m) -> g (g (f n))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse ((f n -> f n)
-> (forall (a :: k). Index10 f a -> m a -> g (n a))
-> f m
-> g (f n)
forall k (f :: (k -> *) -> *) (g :: * -> *) (n :: k -> *) r
       (m :: k -> *).
(Traversable10WithIndex f, Applicative g) =>
(f n -> r)
-> (forall (a :: k). Index10 f a -> m a -> g (n a)) -> f m -> g r
imapTraverse10 f n -> f n
forall a. a -> a
id forall (a :: k). Index10 f a -> m a -> g (n a)
forall (a :: k). Index10 (g :.: f) a -> m a -> g (n a)
f) g (f m)
gfm

-- | 'Data.Ten.Traversable.traverse10' with an index parameter.
itraverse10
  :: (Applicative g, Traversable10WithIndex f)
  => (forall a. Index10 f a -> m a -> g (n a))
  -> f m -> g (f n)
itraverse10 :: (forall (a :: k). Index10 f a -> m a -> g (n a)) -> f m -> g (f n)
itraverse10 = (f n -> f n)
-> (forall (a :: k). Index10 f a -> m a -> g (n a))
-> f m
-> g (f n)
forall k (f :: (k -> *) -> *) (g :: * -> *) (n :: k -> *) r
       (m :: k -> *).
(Traversable10WithIndex f, Applicative g) =>
(f n -> r)
-> (forall (a :: k). Index10 f a -> m a -> g (n a)) -> f m -> g r
imapTraverse10 f n -> f n
forall a. a -> a
id

-- | 'Data.Ten.Traversable.traverse10' with an instance for every element.
traverse10C
  :: forall c f g m n
   . (Entails (Index10 f) c, Applicative g, Traversable10WithIndex f)
  => (forall a. c a => m a -> g (n a)) -> f m -> g (f n)
traverse10C :: (forall (a :: k). c a => m a -> g (n a)) -> f m -> g (f n)
traverse10C forall (a :: k). c a => m a -> g (n a)
f = (forall (a :: k). Index10 f a -> m a -> g (n a)) -> f m -> g (f n)
forall k (g :: * -> *) (f :: (k -> *) -> *) (m :: k -> *)
       (n :: k -> *).
(Applicative g, Traversable10WithIndex f) =>
(forall (a :: k). Index10 f a -> m a -> g (n a)) -> f m -> g (f n)
itraverse10 ((c a => m a -> g (n a)) -> Index10 f a -> m a -> g (n a)
forall k1 (c :: k1 -> Constraint) (k2 :: k1 -> *) (a :: k1) r.
Entails k2 c =>
(c a => r) -> k2 a -> r
byEntailment @c c a => m a -> g (n a)
forall (a :: k). c a => m a -> g (n a)
f)