packages feed

hypertypes-0.2.2: src/Hyper/Class/Apply.hs

-- | A variant of 'Data.Functor.Apply.Apply' for 'Hyper.Type.HyperType's
module Hyper.Class.Apply
    ( HApply (..)
    , HApplicative
    , liftH2
    ) where

import Hyper.Class.Functor (HFunctor (..))
import Hyper.Class.Nodes (HWitness)
import Hyper.Class.Pointed (HPointed)
import Hyper.Type (type (#))

import Hyper.Internal.Prelude

-- | A variant of 'Data.Functor.Apply.Apply' for 'Hyper.Type.HyperType's.
--
-- A type which has 'HApply' and 'HPointed' instances also has 'HApplicative',
-- which is the equivalent to the 'Applicative' class.
class HFunctor h => HApply h where
    -- | Combine child values
    --
    -- >>> hzip (Person name0 age0) (Person name1 age1)
    -- Person (Pair name0 name1) (Pair age0 age1)
    hzip ::
        h # p ->
        h # q ->
        h # (p :*: q)

-- | A variant of 'Applicative' for 'Hyper.Type.HyperType's.
type HApplicative h = (HPointed h, HApply h)

instance Semigroup a => HApply (Const a) where
    {-# INLINE hzip #-}
    hzip (Const x) (Const y) = Const (x <> y)

instance (HApply a, HApply b) => HApply (a :*: b) where
    {-# INLINE hzip #-}
    hzip (a0 :*: b0) (a1 :*: b1) = hzip a0 a1 :*: hzip b0 b1

-- | 'HApply' variant of 'Control.Applicative.liftA2'
{-# INLINE liftH2 #-}
liftH2 ::
    HApply h =>
    (forall n. HWitness h n -> p # n -> q # n -> r # n) ->
    h # p ->
    h # q ->
    h # r
liftH2 f x = hmap (\w (a :*: b) -> f w a b) . hzip x