hypertypes-0.1.0.1: src/Hyper/Combinator/Compose.hs
-- | Compose two 'HyperType's.
--
-- Inspired by [hyperfunctions' @Category@ instance](http://hackage.haskell.org/package/hyperfunctions-0/docs/Control-Monad-Hyper.html).
{-# LANGUAGE UndecidableInstances, FlexibleInstances, FlexibleContexts, TemplateHaskell #-}
module Hyper.Combinator.Compose
( HCompose(..), _HCompose, W_HCompose(..)
, HComposeConstraint1
, decompose, decompose', hcomposed
) where
import Control.Lens (Profunctor, Optic, Iso', iso)
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.Traversable (HTraversable(..), ContainedH(..), htraverse)
import Hyper.Class.Recursive (RNodes(..), Recursively(..), RTraversable)
import Hyper.Class.ZipMatch (ZipMatch(..))
import Hyper.Type (HyperType, GetHyperType, type (#))
import Hyper.Type.Pure (Pure, _Pure)
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]
-- | 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) $
withDict (hComposeConstraint0 p (Proxy @b) w0) $
hLiftConstraint w1 (p1 p w0) $
withDict (d0 p w0 w1) r
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
(HNodes a, 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
<&> hmap
(\_ (HCompose bx :*: HCompose by) -> bx :*: by & HCompose)
<&> (_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' =
withDict (recursively (Proxy @(HFunctor a))) $
withDict (recursively (Proxy @(HFunctor b))) $
_Pure . _HCompose .
hiso
( Proxy @(Recursively HFunctor) #>
_HCompose . hiso ( Proxy @(Recursively HFunctor) #> _HCompose . decompose')
)