    {-# LANGUAGE PackageImports #-}
    {-# LANGUAGE AllowAmbiguousTypes   #-}
    {-# LANGUAGE ConstraintKinds       #-}
    {-# LANGUAGE DataKinds             #-}
    {-# LANGUAGE DefaultSignatures     #-}
    {-# LANGUAGE FlexibleInstances     #-}
    {-# LANGUAGE KindSignatures        #-}
    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE PolyKinds             #-}
    {-# LANGUAGE Rank2Types            #-}
    {-# LANGUAGE ScopedTypeVariables   #-}
    {-# LANGUAGE TypeApplications      #-}
    {-# LANGUAGE TypeFamilies          #-}
    {-# LANGUAGE TypeOperators         #-}
    {-# LANGUAGE UndecidableInstances  #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Data.Generics.Product.Types
    -- Copyright   :  (C) 2020 Csongor Kiss
    -- License     :  BSD3
    -- Maintainer  :  Csongor Kiss <kiss.csongor.kiss@gmail.com>
    -- Stability   :  experimental
    -- Portability :  non-portable
    --
    -- Derive traversals of a given type in a product.
    --
    -----------------------------------------------------------------------------

    module Data.Generics.Product.Types
      ( -- *Traversals
        --
        -- $setup
        Core.HasTypes
      , types

        -- * Custom traversal strategies
        -- $custom
      , Core.Children
      , Core.ChGeneric

      , Core.HasTypesUsing
      , typesUsing

      , Core.HasTypesCustom (typesCustom)
      ) where

    import qualified "generic-lens-core" Data.Generics.Internal.VL.Traversal as VL
    import qualified "generic-lens-core" Data.Generics.Product.Internal.Types as Core

    -- $setup
    -- == /Running example:/
    --
    -- >>> :set -XTypeApplications
    -- >>> :set -XDeriveGeneric
    -- >>> :set -XScopedTypeVariables
    -- >>> import GHC.Generics
    -- >>> :m +Data.Generics.Internal.VL.Traversal
    -- >>> :m +Data.Generics.Internal.VL.Lens
    -- >>> :{
    -- data WTree a w
    --   = Leaf a
    --   | Fork (WTree a w) (WTree a w)
    --   | WithWeight (WTree a w) w
    --   deriving (Generic, Show)
    -- :}

    --------------------------------------------------------------------------------
    -- HasTypes
    --------------------------------------------------------------------------------

    -- | Traverse all types in the given structure.
    --
    -- For example, to update all 'String's in a @WTree (Maybe String) String@, we can write
    --
    -- >>> myTree = WithWeight (Fork (Leaf (Just "hello")) (Leaf Nothing)) "world"
    -- >>> over (types @String) (++ "!") myTree
    -- WithWeight (Fork (Leaf (Just "hello!")) (Leaf Nothing)) "world!"
    --
    -- The traversal is /deep/, which means that not just the immediate
    -- children are visited, but all nested values too.
    types :: forall a s. Core.HasTypes s a => VL.Traversal' s a
    types :: Traversal' s a
    types = Traversal' s a -> (a -> f a) -> s -> f s
    forall (f :: * -> *) s t a b.
    Applicative f =>
    Traversal s t a b -> (a -> f b) -> s -> f t
    VL.confusing (HasTypes s a => Traversal' s a
    forall s a. HasTypes s a => Traversal' s a
    Core.types_ @s @a)
    {-# INLINE types #-}

    --------------------------------------------------------------------------------
    -- HasTypesUsing
    --------------------------------------------------------------------------------

    -- $custom
    --
    -- The default traversal strategy 'types' recurses into each node of the type
    -- using the 'Generic' instance for the nodes. However, in general not all
    -- nodes will have a 'Generic' instance. For example:
    --
    -- >>> data Opaque = Opaque String deriving Show
    -- >>> myTree = WithWeight (Fork (Leaf (Opaque "foo")) (Leaf (Opaque "bar"))) False
    -- >>> over (types @String) (++ "!") myTree
    -- ...
    -- ... | No instance for ‘Generic Opaque’
    -- ... |   arising from a generic traversal.
    -- ... |   Either derive the instance, or define a custom traversal using HasTypesCustom
    -- ...
    --
    -- In these cases, we can define a custom traversal strategy to override the
    -- generic behaviour for certain types.
    -- For a self-contained example, see the CustomChildren module in the tests directory.

    -- | @since 1.2.0.0
    typesUsing :: forall ch a s. Core.HasTypesUsing ch s s a a => VL.Traversal' s a
    typesUsing :: Traversal' s a
    typesUsing = Traversal' s a -> (a -> f a) -> s -> f s
    forall (f :: * -> *) s t a b.
    Applicative f =>
    Traversal s t a b -> (a -> f b) -> s -> f t
    VL.confusing (forall b. HasTypesUsing ch s s a b => Traversal s s a b
    forall ch s t a b. HasTypesUsing ch s t a b => Traversal s t a b
    Core.typesUsing_ @ch @s @s @a)
    {-# INLINE typesUsing #-}