packages feed

hypertypes-0.2.2: src/Hyper/Combinator/Ann.hs

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

module Hyper.Combinator.Ann
    ( Ann (..)
    , hAnn
    , hVal
    , Annotated
    , annotation
    , annValue
    ) where

import Control.Lens (Lens, Lens', from, _Wrapped)
import Hyper.Class.Foldable (HFoldable (..))
import Hyper.Class.Functor (HFunctor (..))
import Hyper.Class.Nodes
import Hyper.Class.Traversable
import Hyper.Combinator.Flip
import Hyper.Recurse
import Hyper.TH.Traversable (makeHTraversableApplyAndBases)
import Hyper.Type (type (#), type (:#))

import Hyper.Internal.Prelude

data Ann a h = Ann
    { _hAnn :: a h
    , _hVal :: h :# Ann a
    }
    deriving (Generic)
makeLenses ''Ann

makeHTraversableApplyAndBases ''Ann
makeCommonInstances [''Ann]

instance RNodes h => HNodes (HFlip Ann h) where
    type HNodesConstraint (HFlip Ann h) c = (Recursive c, c h)
    type HWitnessType (HFlip Ann h) = HRecWitness h
    hLiftConstraint (HWitness HRecSelf) = \_ x -> x
    hLiftConstraint (HWitness (HRecSub w0 w1)) = hLiftConstraintH w0 w1

-- TODO: Dedup this and similar code in Hyper.Unify.Generalize
hLiftConstraintH ::
    forall a c b n r.
    (RNodes a, HNodesConstraint (HFlip Ann a) c) =>
    HWitness a b ->
    HRecWitness b n ->
    Proxy c ->
    (c n => r) ->
    r
hLiftConstraintH c n p f =
    hLiftConstraint
        c
        (Proxy @RNodes)
        ( hLiftConstraint
            c
            p
            (hLiftConstraint (HWitness @(HFlip Ann _) n) p f)
            \\ recurse (Proxy @(c a))
        )
        \\ recurse (Proxy @(RNodes a))

instance RNodes a => RNodes (Ann a) where
    {-# INLINE recursiveHNodes #-}
    recursiveHNodes _ = Dict \\ recursiveHNodes (Proxy @a)

instance (c (Ann a), Recursively c a) => Recursively c (Ann a) where
    {-# INLINE recursively #-}
    recursively _ = Dict \\ recursively (Proxy @(c a))

instance RTraversable a => RTraversable (Ann a) where
    {-# INLINE recursiveHTraversable #-}
    recursiveHTraversable _ = Dict \\ recursiveHTraversable (Proxy @a)

instance Recursively HFunctor h => HFunctor (HFlip Ann h) where
    {-# INLINE hmap #-}
    hmap f =
        _HFlip
            %~ \(Ann a b) ->
                Ann
                    (f (HWitness HRecSelf) a)
                    ( hmap
                        ( Proxy @(Recursively HFunctor) #*#
                            \w -> from _HFlip %~ hmap (f . HWitness . HRecSub w . (^. _HWitness))
                        )
                        b
                        \\ recursively (Proxy @(HFunctor h))
                    )

instance Recursively HFoldable h => HFoldable (HFlip Ann h) where
    {-# INLINE hfoldMap #-}
    hfoldMap f (MkHFlip (Ann a b)) =
        f (HWitness HRecSelf) a
            <> hfoldMap
                ( Proxy @(Recursively HFoldable) #*#
                    \w -> hfoldMap (f . HWitness . HRecSub w . (^. _HWitness)) . MkHFlip
                )
                b
            \\ recursively (Proxy @(HFoldable h))

instance RTraversable h => HTraversable (HFlip Ann h) where
    {-# INLINE hsequence #-}
    hsequence =
        _HFlip
            ( \(Ann a b) ->
                Ann
                    <$> runContainedH a
                    <*> htraverse (Proxy @RTraversable #> from _HFlip hsequence) b
                    \\ recurse (Proxy @(RTraversable h))
            )

type Annotated a = Ann (Const a)

annotation :: Lens' (Annotated a # h) a
annotation = hAnn . _Wrapped

-- | Polymorphic lens to an @Annotated@ value
annValue :: Lens (Annotated a # h0) (Annotated a # h1) (h0 # Annotated a) (h1 # Annotated a)
annValue f (Ann (Const a) b) = f b <&> Ann (Const a)