content: {-# LANGUAGE LambdaCase #-}
  {-# 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 Data.Generics.Internal.Optics hiding (to, QuoteType)
  
  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
  -- >>> import Optics.Core
  -- >>> :{
  -- 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 => Traversal' s a
  types = traversalVL (VL.confusing (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 => Traversal' s a
  typesUsing = traversalVL (VL.confusing (Core.typesUsing_ @ch @s @s @a))
  {-# INLINE typesUsing #-}
  