hypertypes-0.2.2: src/Hyper/Combinator/Compose.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-}
-- | Compose two 'HyperType's.
--
-- Inspired by [hyperfunctions' @Category@ instance](http://hackage.haskell.org/package/hyperfunctions-0/docs/Control-Monad-Hyper.html).
module Hyper.Combinator.Compose
( HCompose (..)
, _HCompose
, W_HCompose (..)
, HComposeConstraint1
, decompose
, decompose'
, hcomposed
) where
import Control.Lens (Iso', Optic, Profunctor, iso)
import Data.Constraint (withDict)
import Hyper.Class.Apply (HApply (..))
import Hyper.Class.Foldable (HFoldable (..))
import Hyper.Class.Functor (HFunctor (..), hiso)
import Hyper.Class.Nodes (HNodes (..), HWitness (..), (#>))
import Hyper.Class.Pointed (HPointed (..))
import Hyper.Class.Recursive (RNodes (..), RTraversable, Recursively (..))
import Hyper.Class.Traversable (ContainedH (..), HTraversable (..), htraverse)
import Hyper.Class.ZipMatch (ZipMatch (..))
import Hyper.Type (GetHyperType, HyperType, type (#))
import Hyper.Type.Pure (Pure, _Pure)
import Text.PrettyPrint.HughesPJClass (Pretty (..))
import Hyper.Internal.Prelude
-- | Compose two 'HyperType's as an external and internal layer
newtype HCompose a b h = HCompose {getHCompose :: a # HCompose b (GetHyperType h)}
deriving stock (Generic)
makeCommonInstances [''HCompose]
instance Pretty (a # HCompose b (GetHyperType h)) => Pretty (HCompose a b h) where
pPrintPrec level prec (HCompose x) = pPrintPrec level prec x
-- | An 'Control.Lens.Iso' for the 'HCompose' @newtype@
{-# INLINE _HCompose #-}
_HCompose ::
Iso
(HCompose a0 b0 # h0)
(HCompose a1 b1 # h1)
(a0 # HCompose b0 h0)
(a1 # HCompose b1 h1)
_HCompose = iso getHCompose HCompose
{-# ANN module "HLint: ignore Use camelCase" #-}
data W_HCompose a b n where
W_HCompose :: HWitness a a0 -> HWitness b b0 -> W_HCompose a b (HCompose a0 b0)
instance (HNodes a, HNodes b) => HNodes (HCompose a b) where
type HNodesConstraint (HCompose a b) c = HNodesConstraint a (HComposeConstraint0 c b)
type HWitnessType (HCompose a b) = W_HCompose a b
{-# INLINE hLiftConstraint #-}
hLiftConstraint (HWitness (W_HCompose w0 w1)) p r =
hLiftConstraint w0 (p0 p) $
hLiftConstraint w1 (p1 p w0) (withDict (d0 p w0 w1) r)
\\ hComposeConstraint0 p (Proxy @b) w0
where
p0 :: Proxy c -> Proxy (HComposeConstraint0 c b)
p0 _ = Proxy
p1 :: proxy0 c -> proxy1 a0 -> Proxy (HComposeConstraint1 c a0)
p1 _ _ = Proxy
d0 ::
HComposeConstraint1 c a0 b0 =>
Proxy c ->
HWitness a a0 ->
HWitness b b0 ->
Dict (c (HCompose a0 b0))
d0 _ _ _ = hComposeConstraint1
class HComposeConstraint0 (c :: HyperType -> Constraint) (b :: HyperType) (h0 :: HyperType) where
hComposeConstraint0 ::
proxy0 c ->
proxy1 b ->
proxy2 h0 ->
Dict (HNodesConstraint b (HComposeConstraint1 c h0))
instance HNodesConstraint b (HComposeConstraint1 c h0) => HComposeConstraint0 c b h0 where
{-# INLINE hComposeConstraint0 #-}
hComposeConstraint0 _ _ _ = Dict
class HComposeConstraint1 (c :: HyperType -> Constraint) (h0 :: HyperType) (h1 :: HyperType) where
hComposeConstraint1 :: Dict (c (HCompose h0 h1))
instance c (HCompose h0 h1) => HComposeConstraint1 c h0 h1 where
{-# INLINE hComposeConstraint1 #-}
hComposeConstraint1 = Dict
instance
(HPointed a, HPointed b) =>
HPointed (HCompose a b)
where
{-# INLINE hpure #-}
hpure x =
_HCompose
# hpure
( \wa ->
_HCompose # hpure (\wb -> _HCompose # x (HWitness (W_HCompose wa wb)))
)
instance (HFunctor a, HFunctor b) => HFunctor (HCompose a b) where
{-# INLINE hmap #-}
hmap f =
_HCompose
%~ hmap
( \w0 ->
_HCompose %~ hmap (\w1 -> _HCompose %~ f (HWitness (W_HCompose w0 w1)))
)
instance (HApply a, HApply b) => HApply (HCompose a b) where
{-# INLINE hzip #-}
hzip (HCompose a0) =
_HCompose
%~ hmap
( \_ (HCompose b0 :*: HCompose b1) ->
_HCompose
# hmap
( \_ (HCompose i0 :*: HCompose i1) ->
_HCompose # (i0 :*: i1)
)
(hzip b0 b1)
)
. hzip a0
instance (HFoldable a, HFoldable b) => HFoldable (HCompose a b) where
{-# INLINE hfoldMap #-}
hfoldMap f =
hfoldMap
( \w0 ->
hfoldMap (\w1 -> f (HWitness (W_HCompose w0 w1)) . (^. _HCompose)) . (^. _HCompose)
)
. (^. _HCompose)
instance (HTraversable a, HTraversable b) => HTraversable (HCompose a b) where
{-# INLINE hsequence #-}
hsequence =
_HCompose
( hsequence
. hmap (const (MkContainedH . _HCompose (htraverse (const (_HCompose runContainedH)))))
)
instance
(ZipMatch h0, ZipMatch h1, HTraversable h0, HFunctor h1) =>
ZipMatch (HCompose h0 h1)
where
{-# INLINE zipMatch #-}
zipMatch (HCompose x) (HCompose y) =
zipMatch x y
>>= htraverse
( \_ (HCompose cx :*: HCompose cy) ->
zipMatch cx cy
<&> (_HCompose #) . hmap (\_ (HCompose bx :*: HCompose by) -> bx :*: by & HCompose)
)
<&> (_HCompose #)
instance
( HNodes a
, HNodes b
, HNodesConstraint a (HComposeConstraint0 RNodes b)
) =>
RNodes (HCompose a b)
instance
( HNodes h0
, HNodes h1
, c (HCompose h0 h1)
, HNodesConstraint h0 (HComposeConstraint0 RNodes h1)
, HNodesConstraint h0 (HComposeConstraint0 (Recursively c) h1)
) =>
Recursively c (HCompose h0 h1)
instance
( HTraversable a
, HTraversable b
, HNodesConstraint a (HComposeConstraint0 RNodes b)
, HNodesConstraint a (HComposeConstraint0 (Recursively HFunctor) b)
, HNodesConstraint a (HComposeConstraint0 (Recursively HFoldable) b)
, HNodesConstraint a (HComposeConstraint0 RTraversable b)
) =>
RTraversable (HCompose a b)
hcomposed ::
(Profunctor p, Functor f) =>
Optic
p
f
(a0 # HCompose b0 c0)
(a1 # HCompose b1 c1)
(HCompose a2 b2 # c2)
(HCompose a3 b3 # c3) ->
Optic
p
f
(HCompose a0 b0 # c0)
(HCompose a1 b1 # c1)
(a2 # HCompose b2 c2)
(a3 # HCompose b3 c3)
hcomposed f = _HCompose . f . _HCompose
-- | Inject Pure between two hypertypes.
decompose ::
forall a0 b0 a1 b1.
(Recursively HFunctor a0, Recursively HFunctor b0, Recursively HFunctor a1, Recursively HFunctor b1) =>
Iso (Pure # HCompose a0 b0) (Pure # HCompose a1 b1) (a0 # b0) (a1 # b1)
decompose = iso (^. decompose') (decompose' #)
decompose' ::
forall a b.
(Recursively HFunctor a, Recursively HFunctor b) =>
Iso' (Pure # HCompose a b) (a # b)
decompose' =
_Pure
. _HCompose
. hiso
( Proxy @(Recursively HFunctor) #>
_HCompose
. hiso (Proxy @(Recursively HFunctor) #> _HCompose . decompose')
\\ recursively (Proxy @(HFunctor b))
)
\\ recursively (Proxy @(HFunctor a))