-- 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 'Foldable10' 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.Foldable.WithIndex
         ( Index10, Foldable10WithIndex(..)
         , ifoldl10, ifoldr10, itraverse10_
         , foldMap10C, foldr10C, foldl10C, traverse10C_
         ) where

import Data.Monoid (Dual(..), Endo(..))

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

import Data.Ten.Entails (Entails(..), byEntailment)
import Data.Ten.Foldable (Foldable10(..))
import Data.Ten.Functor.WithIndex (Index10)

-- | An extension of 'Foldable10' that provides access to some 'Index10'.
class Foldable10 f => Foldable10WithIndex f where
  ifoldMap10 :: Monoid w => (forall a. Index10 f a -> m a -> w) -> f m -> w

instance (Foldable g, Foldable10WithIndex f)
      => Foldable10WithIndex (g :.: f) where
  ifoldMap10 :: (forall (a :: k). Index10 (g :.: f) a -> m a -> w)
-> (:.:) g f m -> w
ifoldMap10 forall (a :: k). Index10 (g :.: f) a -> m a -> w
f (Comp1 g (f m)
gfm) = (f m -> w) -> g (f m) -> w
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap ((forall (a :: k). Index10 f a -> m a -> w) -> f m -> w
forall k (f :: (k -> *) -> *) w (m :: k -> *).
(Foldable10WithIndex f, Monoid w) =>
(forall (a :: k). Index10 f a -> m a -> w) -> f m -> w
ifoldMap10 forall (a :: k). Index10 f a -> m a -> w
forall (a :: k). Index10 (g :.: f) a -> m a -> w
f) g (f m)
gfm

-- | 'Data.Ten.Foldable.foldl10' with an index parameter.
ifoldl10
  :: Foldable10WithIndex f
  => (forall a. Index10 f a -> b -> m a -> b)
  -> b -> f m -> b
ifoldl10 :: (forall (a :: k). Index10 f a -> b -> m a -> b) -> b -> f m -> b
ifoldl10 forall (a :: k). Index10 f a -> b -> m a -> b
f b
z f m
fm = Endo b -> b -> b
forall a. Endo a -> a -> a
appEndo ((forall (a :: k). Index10 f a -> m a -> Endo b) -> f m -> Endo b
forall k (f :: (k -> *) -> *) w (m :: k -> *).
(Foldable10WithIndex f, Monoid w) =>
(forall (a :: k). Index10 f a -> m a -> w) -> f m -> w
ifoldMap10 (\Index10 f a
i m a
x -> (b -> b) -> Endo b
forall a. (a -> a) -> Endo a
Endo (\b
b -> Index10 f a -> b -> m a -> b
forall (a :: k). Index10 f a -> b -> m a -> b
f Index10 f a
i b
b m a
x)) f m
fm) b
z

-- | 'Data.Ten.Foldable.foldr10' with an index parameter.
ifoldr10
  :: Foldable10WithIndex f
  => (forall a. Index10 f a -> m a -> b -> b) -> b -> f m -> b
ifoldr10 :: (forall (a :: k). Index10 f a -> m a -> b -> b) -> b -> f m -> b
ifoldr10 forall (a :: k). Index10 f a -> m a -> b -> b
f b
z f m
fm = (Endo b -> b -> b) -> b -> Endo b -> b
forall a b c. (a -> b -> c) -> b -> a -> c
flip Endo b -> b -> b
forall a. Endo a -> a -> a
appEndo b
z (Endo b -> b) -> Endo b -> b
forall a b. (a -> b) -> a -> b
$ Dual (Endo b) -> Endo b
forall a. Dual a -> a
getDual (Dual (Endo b) -> Endo b) -> Dual (Endo b) -> Endo b
forall a b. (a -> b) -> a -> b
$
  (forall (a :: k). Index10 f a -> m a -> Dual (Endo b))
-> f m -> Dual (Endo b)
forall k (f :: (k -> *) -> *) w (m :: k -> *).
(Foldable10WithIndex f, Monoid w) =>
(forall (a :: k). Index10 f a -> m a -> w) -> f m -> w
ifoldMap10 (\Index10 f a
i m a
x -> Endo b -> Dual (Endo b)
forall a. a -> Dual a
Dual (Endo b -> Dual (Endo b)) -> Endo b -> Dual (Endo b)
forall a b. (a -> b) -> a -> b
$ (b -> b) -> Endo b
forall a. (a -> a) -> Endo a
Endo (Index10 f a -> m a -> b -> b
forall (a :: k). Index10 f a -> m a -> b -> b
f Index10 f a
i m a
x)) f m
fm

-- | 'Data.Ten.Foldable.traverse10_' with an index parameter.
itraverse10_
  :: (Foldable10WithIndex f, Applicative g)
  => (forall a. Index10 f a -> m a -> g ())
  -> f m -> g ()
itraverse10_ :: (forall (a :: k). Index10 f a -> m a -> g ()) -> f m -> g ()
itraverse10_ forall (a :: k). Index10 f a -> m a -> g ()
f = (forall (a :: k). Index10 f a -> g () -> m a -> g ())
-> g () -> f m -> g ()
forall k (f :: (k -> *) -> *) b (m :: k -> *).
Foldable10WithIndex f =>
(forall (a :: k). Index10 f a -> b -> m a -> b) -> b -> f m -> b
ifoldl10 (\Index10 f a
i g ()
a m a
x -> g ()
a g () -> g () -> g ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* Index10 f a -> m a -> g ()
forall (a :: k). Index10 f a -> m a -> g ()
f Index10 f a
i m a
x) (() -> g ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ())

-- | 'Data.Ten.Foldable.foldMap10' with an instance for every element.
foldMap10C
  :: forall c f m w
   . (Entails (Index10 f) c, Foldable10WithIndex f, Monoid w)
  => (forall a. c a => m a -> w) -> f m -> w
foldMap10C :: (forall (a :: k). c a => m a -> w) -> f m -> w
foldMap10C forall (a :: k). c a => m a -> w
f = (forall (a :: k). Index10 f a -> m a -> w) -> f m -> w
forall k (f :: (k -> *) -> *) w (m :: k -> *).
(Foldable10WithIndex f, Monoid w) =>
(forall (a :: k). Index10 f a -> m a -> w) -> f m -> w
ifoldMap10 ((c a => m a -> w) -> Index10 f a -> m a -> w
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 -> w
forall (a :: k). c a => m a -> w
f)

-- | 'Data.Ten.Foldable.foldr10' with an instance for every element.
foldr10C
  :: forall c f m b
   . (Entails (Index10 f) c, Foldable10WithIndex f)
  => (forall a. c a => m a -> b -> b) -> b -> f m -> b
foldr10C :: (forall (a :: k). c a => m a -> b -> b) -> b -> f m -> b
foldr10C forall (a :: k). c a => m a -> b -> b
f = (forall (a :: k). Index10 f a -> m a -> b -> b) -> b -> f m -> b
forall k (f :: (k -> *) -> *) (m :: k -> *) b.
Foldable10WithIndex f =>
(forall (a :: k). Index10 f a -> m a -> b -> b) -> b -> f m -> b
ifoldr10 ((c a => m a -> b -> b) -> Index10 f a -> m a -> b -> b
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 -> b -> b
forall (a :: k). c a => m a -> b -> b
f)

-- | 'Data.Ten.Foldable.foldl10' with an instance for every element.
foldl10C
  :: forall c f m b
   . (Entails (Index10 f) c, Foldable10WithIndex f)
  => (forall a. c a => b -> m a -> b) -> b -> f m -> b
foldl10C :: (forall (a :: k). c a => b -> m a -> b) -> b -> f m -> b
foldl10C forall (a :: k). c a => b -> m a -> b
f = (forall (a :: k). Index10 f a -> b -> m a -> b) -> b -> f m -> b
forall k (f :: (k -> *) -> *) b (m :: k -> *).
Foldable10WithIndex f =>
(forall (a :: k). Index10 f a -> b -> m a -> b) -> b -> f m -> b
ifoldl10 ((c a => b -> m a -> b) -> Index10 f a -> b -> m a -> b
forall k1 (c :: k1 -> Constraint) (k2 :: k1 -> *) (a :: k1) r.
Entails k2 c =>
(c a => r) -> k2 a -> r
byEntailment @c c a => b -> m a -> b
forall (a :: k). c a => b -> m a -> b
f)

-- | 'Data.Ten.Foldable.traverse10_' with an instance for every element.
traverse10C_
  :: forall c f g m
   . (Entails (Index10 f) c, Applicative g, Foldable10WithIndex f)
  => (forall a. c a => m a -> g ()) -> f m -> g ()
traverse10C_ :: (forall (a :: k). c a => m a -> g ()) -> f m -> g ()
traverse10C_ forall (a :: k). c a => m a -> g ()
f = (forall (a :: k). Index10 f a -> m a -> g ()) -> f m -> g ()
forall k (f :: (k -> *) -> *) (g :: * -> *) (m :: k -> *).
(Foldable10WithIndex f, Applicative g) =>
(forall (a :: k). Index10 f a -> m a -> g ()) -> f m -> g ()
itraverse10_ ((c a => m a -> g ()) -> Index10 f a -> m a -> g ()
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 ()
forall (a :: k). c a => m a -> g ()
f)