{-# LANGUAGE UndecidableInstances, TemplateHaskell, FlexibleInstances #-}

-- | A simple 'Hyper.Type.HyperType' with a single child node

module Hyper.Combinator.ANode
    ( ANode(..), _ANode, W_ANode(..), MorphWitness(..)
    ) where

import Control.Lens (iso)
import Hyper.Class.Optic (HNodeLens(..))
import Hyper.Class.Morph (HMorph(..))
import Hyper.Class.Recursive (RNodes, Recursively, RTraversable)
import Hyper.TH.Traversable (makeHTraversableApplyAndBases)
import Hyper.Type (type (#), type (:#))

import Hyper.Internal.Prelude

-- | @ANode c@ is a 'Hyper.Type.HyperType' with a single child node of type @c@
newtype ANode c h = MkANode (h :# c)
    deriving stock (forall x. ANode c h -> Rep (ANode c h) x)
-> (forall x. Rep (ANode c h) x -> ANode c h)
-> Generic (ANode c h)
forall x. Rep (ANode c h) x -> ANode c h
forall x. ANode c h -> Rep (ANode c h) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (c :: HyperType) (h :: AHyperType) x.
Rep (ANode c h) x -> ANode c h
forall (c :: HyperType) (h :: AHyperType) x.
ANode c h -> Rep (ANode c h) x
$cto :: forall (c :: HyperType) (h :: AHyperType) x.
Rep (ANode c h) x -> ANode c h
$cfrom :: forall (c :: HyperType) (h :: AHyperType) x.
ANode c h -> Rep (ANode c h) x
Generic

-- | An 'Iso' from 'ANode' its child node.
--
-- Using `_ANode` rather than the 'MkANode' data constructor is recommended,
-- because it helps the type inference know that @ANode c@ is parameterized with a 'Hyper.Type.HyperType'.
{-# INLINE _ANode #-}
_ANode :: Iso (ANode c0 # k0) (ANode c1 # k1) (k0 # c0) (k1 # c1)
_ANode :: p (k0 # c0) (f (k1 # c1)) -> p (ANode c0 # k0) (f (ANode c1 # k1))
_ANode = ((ANode c0 # k0) -> k0 # c0)
-> ((k1 # c1) -> ANode c1 # k1)
-> Iso (ANode c0 # k0) (ANode c1 # k1) (k0 # c0) (k1 # c1)
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso (\(MkANode 'AHyperType k0 :# c0
x) -> k0 # c0
'AHyperType k0 :# c0
x) (k1 # c1) -> ANode c1 # k1
forall (c :: HyperType) (h :: AHyperType). (h :# c) -> ANode c h
MkANode

makeHTraversableApplyAndBases ''ANode
makeCommonInstances [''ANode]

instance HNodeLens (ANode c) c where hNodeLens :: ((h # c) -> f (h # c)) -> (ANode c # h) -> f (ANode c # h)
hNodeLens = ((h # c) -> f (h # c)) -> (ANode c # h) -> f (ANode c # h)
forall (c0 :: HyperType) (k0 :: HyperType) (c1 :: HyperType)
       (k1 :: HyperType).
Iso (ANode c0 # k0) (ANode c1 # k1) (k0 # c0) (k1 # c1)
_ANode

instance RNodes n => RNodes (ANode n)
instance (c (ANode n), Recursively c n) => Recursively c (ANode n)
instance RTraversable n => RTraversable (ANode n)

instance HMorph (ANode a) (ANode b) where
    type instance MorphConstraint (ANode a) (ANode b) c = c a b
    data instance MorphWitness (ANode a) (ANode b) _ _ where
        M_ANode :: MorphWitness (ANode a) (ANode b) a b
    morphMap :: (forall (a :: HyperType) (b :: HyperType).
 MorphWitness (ANode a) (ANode b) a b -> (p # a) -> q # b)
-> (ANode a # p) -> ANode b # q
morphMap forall (a :: HyperType) (b :: HyperType).
MorphWitness (ANode a) (ANode b) a b -> (p # a) -> q # b
f = ((p # a) -> Identity (q # b))
-> (ANode a # p) -> Identity (ANode b # q)
forall (c0 :: HyperType) (k0 :: HyperType) (c1 :: HyperType)
       (k1 :: HyperType).
Iso (ANode c0 # k0) (ANode c1 # k1) (k0 # c0) (k1 # c1)
_ANode (((p # a) -> Identity (q # b))
 -> (ANode a # p) -> Identity (ANode b # q))
-> ((p # a) -> q # b) -> (ANode a # p) -> ANode b # q
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ MorphWitness (ANode a) (ANode b) a b -> (p # a) -> q # b
forall (a :: HyperType) (b :: HyperType).
MorphWitness (ANode a) (ANode b) a b -> (p # a) -> q # b
f MorphWitness (ANode a) (ANode b) a b
forall (a :: HyperType) (b :: HyperType).
MorphWitness (ANode a) (ANode b) a b
M_ANode
    morphLiftConstraint :: MorphWitness (ANode a) (ANode b) a b
-> Proxy c -> (c a b => r) -> r
morphLiftConstraint MorphWitness (ANode a) (ANode b) a b
M_ANode Proxy c
_ c a b => r
x = r
c a b => r
x