{-# Language FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, RankNTypes, TypeFamilies, TypeOperators #-}

module Transformation.Full where

import qualified Data.Functor
import           Data.Functor.Compose (Compose(Compose, getCompose))
import           Data.Functor.Const (Const(Const, getConst))
import           Data.Kind (Type)
import qualified Data.Foldable
import qualified Data.Traversable
import qualified Rank2
import qualified Transformation
import           Transformation (Transformation, Domain, Codomain)
import {-# SOURCE #-} qualified Transformation.Deep as Deep

import Prelude hiding (Foldable(..), Traversable(..), Functor(..), Applicative(..), (<$>), fst, snd)

-- | Like 'Deep.Functor' except it maps an additional wrapper around the entire tree
class (Transformation t, Rank2.Functor (g (Domain t))) => Functor t g where
   (<$>) :: t -> Domain t (g (Domain t) (Domain t)) -> Codomain t (g (Codomain t) (Codomain t))

-- | Like 'Deep.Foldable' except the entire tree is also wrapped
class (Transformation t, Rank2.Foldable (g (Domain t))) => Foldable t g where
   foldMap :: (Codomain t ~ Const m, Monoid m) => t -> Domain t (g (Domain t) (Domain t)) -> m

-- | Like 'Deep.Traversable' except it traverses an additional wrapper around the entire tree
class (Transformation t, Rank2.Traversable (g (Domain t))) => Traversable t g where
   traverse :: Codomain t ~ Compose m f => t -> Domain t (g (Domain t) (Domain t)) -> m (f (g f f))

-- | Alphabetical synonym for '<$>'
fmap :: Functor t g => t -> Domain t (g (Domain t) (Domain t)) -> Codomain t (g (Codomain t) (Codomain t))
fmap :: t
-> Domain t (g (Domain t) (Domain t))
-> Codomain t (g (Codomain t) (Codomain t))
fmap = t
-> Domain t (g (Domain t) (Domain t))
-> Codomain t (g (Codomain t) (Codomain t))
forall t (g :: (* -> *) -> (* -> *) -> *).
Functor t g =>
t
-> Domain t (g (Domain t) (Domain t))
-> Codomain t (g (Codomain t) (Codomain t))
(<$>)

-- | Default implementation for '<$>' that maps the wrapper and then the tree
mapDownDefault :: (Deep.Functor t g, t `Transformation.At` g (Domain t) (Domain t), Data.Functor.Functor (Codomain t))
               => t -> Domain t (g (Domain t) (Domain t)) -> Codomain t (g (Codomain t) (Codomain t))
mapDownDefault :: t
-> Domain t (g (Domain t) (Domain t))
-> Codomain t (g (Codomain t) (Codomain t))
mapDownDefault t :: t
t x :: Domain t (g (Domain t) (Domain t))
x = (t
t t -> g (Domain t) (Domain t) -> g (Codomain t) (Codomain t)
forall t (g :: (* -> *) -> (* -> *) -> *).
Functor t g =>
t -> g (Domain t) (Domain t) -> g (Codomain t) (Codomain t)
Deep.<$>) (g (Domain t) (Domain t) -> g (Codomain t) (Codomain t))
-> Codomain t (g (Domain t) (Domain t))
-> Codomain t (g (Codomain t) (Codomain t))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
Data.Functor.<$> (t
t t
-> Domain t (g (Domain t) (Domain t))
-> Codomain t (g (Domain t) (Domain t))
forall t x. At t x => t -> Domain t x -> Codomain t x
Transformation.$ Domain t (g (Domain t) (Domain t))
x)

-- | Default implementation for '<$>' that maps the tree and then the wrapper
mapUpDefault   :: (Deep.Functor t g, t `Transformation.At` g (Codomain t) (Codomain t), Data.Functor.Functor (Domain t))
               => t -> Domain t (g (Domain t) (Domain t)) -> Codomain t (g (Codomain t) (Codomain t))
mapUpDefault :: t
-> Domain t (g (Domain t) (Domain t))
-> Codomain t (g (Codomain t) (Codomain t))
mapUpDefault   t :: t
t x :: Domain t (g (Domain t) (Domain t))
x = t
t t
-> Domain t (g (Codomain t) (Codomain t))
-> Codomain t (g (Codomain t) (Codomain t))
forall t x. At t x => t -> Domain t x -> Codomain t x
Transformation.$ ((t
t t -> g (Domain t) (Domain t) -> g (Codomain t) (Codomain t)
forall t (g :: (* -> *) -> (* -> *) -> *).
Functor t g =>
t -> g (Domain t) (Domain t) -> g (Codomain t) (Codomain t)
Deep.<$>) (g (Domain t) (Domain t) -> g (Codomain t) (Codomain t))
-> Domain t (g (Domain t) (Domain t))
-> Domain t (g (Codomain t) (Codomain t))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
Data.Functor.<$> Domain t (g (Domain t) (Domain t))
x)

foldMapDownDefault, foldMapUpDefault :: (t `Transformation.At` g (Domain t) (Domain t), Deep.Foldable t g,
                                         Codomain t ~ Const m, Data.Foldable.Foldable (Domain t), Monoid m)
                                     => t -> Domain t (g (Domain t) (Domain t)) -> m
-- | Default implementation for 'foldMap' that folds the wrapper and then the tree
foldMapDownDefault :: t -> Domain t (g (Domain t) (Domain t)) -> m
foldMapDownDefault t :: t
t x :: Domain t (g (Domain t) (Domain t))
x = Const m (g (Domain t) (Domain t)) -> m
forall a k (b :: k). Const a b -> a
getConst (t
t t
-> Domain t (g (Domain t) (Domain t))
-> Codomain t (g (Domain t) (Domain t))
forall t x. At t x => t -> Domain t x -> Codomain t x
Transformation.$ Domain t (g (Domain t) (Domain t))
x) m -> m -> m
forall a. Semigroup a => a -> a -> a
<> (g (Domain t) (Domain t) -> m)
-> Domain t (g (Domain t) (Domain t)) -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
Data.Foldable.foldMap (t -> g (Domain t) (Domain t) -> m
forall t (g :: (* -> *) -> (* -> *) -> *) m.
(Foldable t g, Codomain t ~ Const m, Monoid m) =>
t -> g (Domain t) (Domain t) -> m
Deep.foldMap t
t) Domain t (g (Domain t) (Domain t))
x
-- | Default implementation for 'foldMap' that folds the tree and then the wrapper
foldMapUpDefault :: t -> Domain t (g (Domain t) (Domain t)) -> m
foldMapUpDefault   t :: t
t x :: Domain t (g (Domain t) (Domain t))
x = (g (Domain t) (Domain t) -> m)
-> Domain t (g (Domain t) (Domain t)) -> m
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
Data.Foldable.foldMap (t -> g (Domain t) (Domain t) -> m
forall t (g :: (* -> *) -> (* -> *) -> *) m.
(Foldable t g, Codomain t ~ Const m, Monoid m) =>
t -> g (Domain t) (Domain t) -> m
Deep.foldMap t
t) Domain t (g (Domain t) (Domain t))
x m -> m -> m
forall a. Semigroup a => a -> a -> a
<> Const m (g (Domain t) (Domain t)) -> m
forall a k (b :: k). Const a b -> a
getConst (t
t t
-> Domain t (g (Domain t) (Domain t))
-> Codomain t (g (Domain t) (Domain t))
forall t x. At t x => t -> Domain t x -> Codomain t x
Transformation.$ Domain t (g (Domain t) (Domain t))
x)

-- | Default implementation for 'traverse' that traverses the wrapper and then the tree
traverseDownDefault :: (Deep.Traversable t g, t `Transformation.At` g (Domain t) (Domain t),
                        Codomain t ~ Compose m f, Data.Traversable.Traversable f, Monad m)
                    => t -> Domain t (g (Domain t) (Domain t)) -> m (f (g f f))
traverseDownDefault :: t -> Domain t (g (Domain t) (Domain t)) -> m (f (g f f))
traverseDownDefault t :: t
t x :: Domain t (g (Domain t) (Domain t))
x = Compose m f (g (Domain t) (Domain t))
-> m (f (g (Domain t) (Domain t)))
forall k1 (f :: k1 -> *) k2 (g :: k2 -> k1) (a :: k2).
Compose f g a -> f (g a)
getCompose (t
t t
-> Domain t (g (Domain t) (Domain t))
-> Codomain t (g (Domain t) (Domain t))
forall t x. At t x => t -> Domain t x -> Codomain t x
Transformation.$ Domain t (g (Domain t) (Domain t))
x) m (f (g (Domain t) (Domain t)))
-> (f (g (Domain t) (Domain t)) -> m (f (g f f))) -> m (f (g f f))
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (g (Domain t) (Domain t) -> m (g f f))
-> f (g (Domain t) (Domain t)) -> m (f (g f f))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
Data.Traversable.traverse (t -> g (Domain t) (Domain t) -> m (g f f)
forall t (g :: (* -> *) -> (* -> *) -> *) (m :: * -> *)
       (f :: * -> *).
(Traversable t g, Codomain t ~ Compose m f) =>
t -> g (Domain t) (Domain t) -> m (g f f)
Deep.traverse t
t)

-- | Default implementation for 'traverse' that traverses the tree and then the wrapper
traverseUpDefault   :: (Deep.Traversable t g, Codomain t ~ Compose m f, t `Transformation.At` g f f,
                        Data.Traversable.Traversable (Domain t), Monad m)
                    => t -> Domain t (g (Domain t) (Domain t)) -> m (f (g f f))
traverseUpDefault :: t -> Domain t (g (Domain t) (Domain t)) -> m (f (g f f))
traverseUpDefault   t :: t
t x :: Domain t (g (Domain t) (Domain t))
x = (g (Domain t) (Domain t) -> m (g f f))
-> Domain t (g (Domain t) (Domain t)) -> m (Domain t (g f f))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
Data.Traversable.traverse (t -> g (Domain t) (Domain t) -> m (g f f)
forall t (g :: (* -> *) -> (* -> *) -> *) (m :: * -> *)
       (f :: * -> *).
(Traversable t g, Codomain t ~ Compose m f) =>
t -> g (Domain t) (Domain t) -> m (g f f)
Deep.traverse t
t) Domain t (g (Domain t) (Domain t))
x m (Domain t (g f f))
-> (Domain t (g f f) -> m (f (g f f))) -> m (f (g f f))
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Compose m f (g f f) -> m (f (g f f))
forall k1 (f :: k1 -> *) k2 (g :: k2 -> k1) (a :: k2).
Compose f g a -> f (g a)
getCompose (Compose m f (g f f) -> m (f (g f f)))
-> (Domain t (g f f) -> Compose m f (g f f))
-> Domain t (g f f)
-> m (f (g f f))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (t
t t -> Domain t (g f f) -> Codomain t (g f f)
forall t x. At t x => t -> Domain t x -> Codomain t x
Transformation.$)