{-# LANGUAGE AllowAmbiguousTypes #-}

{- | 'traverse' for generic data types.

TODO This is harder to conceptualize than generic 'foldMap'. No nice clean
explanation yet.

This function can provide generic support for simple parser-esque types.
-}

module Generic.Data.Function.Traverse
  ( GenericTraverse(..)
  , genericTraverseNonSum , GTraverseNonSum
  , genericTraverseSum,     GTraverseSum
  , genericTraverseSumRaw
  ) where

import GHC.Generics

import Generic.Data.Function.Traverse.NonSum
import Generic.Data.Function.Traverse.Sum
import Generic.Data.Function.Traverse.Constructor
import Generic.Data.MetaParse.Cstr
import GHC.TypeLits ( symbolVal' )

-- | Generic 'traverse' over a term of non-sum data type @f a@,
--   where @f@ is set by the @tag@ you pass.
genericTraverseNonSum
    :: forall {k} (tag :: k) a
    .  ( Generic a
       , Functor (GenericTraverseF tag)
       , GTraverseNonSum tag (Rep a)
    ) => GenericTraverseF tag a
genericTraverseNonSum :: forall {k} (tag :: k) a.
(Generic a, Functor (GenericTraverseF tag),
 GTraverseNonSum tag (Rep a)) =>
GenericTraverseF tag a
genericTraverseNonSum = Rep a Any -> a
forall a x. Generic a => Rep a x -> a
forall x. Rep a x -> a
to (Rep a Any -> a)
-> GenericTraverseF tag (Rep a Any) -> GenericTraverseF tag a
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (tag :: k) (gf :: Type -> Type) p.
GTraverseNonSum tag gf =>
GenericTraverseF tag (gf p)
forall {k} {k1} (tag :: k) (gf :: k1 -> Type) (p :: k1).
GTraverseNonSum tag gf =>
GenericTraverseF tag (gf p)
gTraverseNonSum @tag

genericTraverseSum
    :: forall tag sumtag a pt
    .  ( Generic a
       , Functor (GenericTraverseF tag)
       , GTraverseSum tag sumtag (Rep a)
    ) => ParseCstrTo sumtag pt
      -> (String -> GenericTraverseF tag pt)
      -> (forall x. String -> GenericTraverseF tag x)
      -> (pt -> pt -> Bool)
      -> GenericTraverseF tag a
genericTraverseSum :: forall {k} {k} (tag :: k) (sumtag :: k) a pt.
(Generic a, Functor (GenericTraverseF tag),
 GTraverseSum tag sumtag (Rep a)) =>
ParseCstrTo sumtag pt
-> (String -> GenericTraverseF tag pt)
-> (forall x. String -> GenericTraverseF tag x)
-> (pt -> pt -> Bool)
-> GenericTraverseF tag a
genericTraverseSum ParseCstrTo sumtag pt
parseCstr String -> GenericTraverseF tag pt
ptGet forall x. String -> GenericTraverseF tag x
fNoMatch pt -> pt -> Bool
ptEq =
    Rep a Any -> a
forall a x. Generic a => Rep a x -> a
forall x. Rep a x -> a
to (Rep a Any -> a)
-> GenericTraverseF tag (Rep a Any) -> GenericTraverseF tag a
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (tag :: k) (sumtag :: k) (gf :: Type -> Type) pt p.
GTraverseSum tag sumtag gf =>
ParseCstrTo sumtag pt
-> (String -> GenericTraverseF tag pt)
-> (forall a. String -> GenericTraverseF tag a)
-> (pt -> pt -> Bool)
-> GenericTraverseF tag (gf p)
forall {k} {k1} {k2} (tag :: k) (sumtag :: k1) (gf :: k2 -> Type)
       pt (p :: k2).
GTraverseSum tag sumtag gf =>
ParseCstrTo sumtag pt
-> (String -> GenericTraverseF tag pt)
-> (forall a. String -> GenericTraverseF tag a)
-> (pt -> pt -> Bool)
-> GenericTraverseF tag (gf p)
gTraverseSum @tag @sumtag Proxy# x -> pt
ParseCstrTo sumtag pt
parseCstr String -> GenericTraverseF tag pt
ptGet String -> GenericTraverseF tag a
forall x. String -> GenericTraverseF tag x
fNoMatch pt -> pt -> Bool
ptEq

genericTraverseSumRaw
    :: forall tag a pt
    .  ( Generic a
       , Functor (GenericTraverseF tag)
       , GTraverseSum tag Raw (Rep a)
    ) => (String -> pt)
      -> (String -> GenericTraverseF tag pt)
      -> (forall x. String -> GenericTraverseF tag x)
      -> (pt -> pt -> Bool)
      -> GenericTraverseF tag a
genericTraverseSumRaw :: forall {k} (tag :: k) a pt.
(Generic a, Functor (GenericTraverseF tag),
 GTraverseSum tag Raw (Rep a)) =>
(String -> pt)
-> (String -> GenericTraverseF tag pt)
-> (forall x. String -> GenericTraverseF tag x)
-> (pt -> pt -> Bool)
-> GenericTraverseF tag a
genericTraverseSumRaw String -> pt
parseCstr String -> GenericTraverseF tag pt
ptGet forall x. String -> GenericTraverseF tag x
fNoMatch pt -> pt -> Bool
ptEq = Rep a Any -> a
forall a x. Generic a => Rep a x -> a
forall x. Rep a x -> a
to (Rep a Any -> a)
-> GenericTraverseF tag (Rep a Any) -> GenericTraverseF tag a
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$>
    forall (tag :: k) sumtag (gf :: Type -> Type) pt p.
GTraverseSum tag sumtag gf =>
ParseCstrTo sumtag pt
-> (String -> GenericTraverseF tag pt)
-> (forall a. String -> GenericTraverseF tag a)
-> (pt -> pt -> Bool)
-> GenericTraverseF tag (gf p)
forall {k} {k1} {k2} (tag :: k) (sumtag :: k1) (gf :: k2 -> Type)
       pt (p :: k2).
GTraverseSum tag sumtag gf =>
ParseCstrTo sumtag pt
-> (String -> GenericTraverseF tag pt)
-> (forall a. String -> GenericTraverseF tag a)
-> (pt -> pt -> Bool)
-> GenericTraverseF tag (gf p)
gTraverseSum @tag @Raw (\Proxy# x
p -> String -> pt
parseCstr (Proxy# x -> String
forall (n :: Symbol). KnownSymbol n => Proxy# n -> String
symbolVal' Proxy# x
Proxy# x
p)) String -> GenericTraverseF tag pt
ptGet String -> GenericTraverseF tag a
forall x. String -> GenericTraverseF tag x
fNoMatch pt -> pt -> Bool
ptEq