packages feed

ptera-core-0.2.0.0: src/Language/Parser/Ptera/Data/HFList.hs

module Language.Parser.Ptera.Data.HFList (
    T,
    HFList (..),
    Membership,

    Concat,
    hconcat,

    hfoldrWithIndex,
    htraverseWithIndex,
    hmapWithIndex,
    hfoldMWithIndex,
    hforMWithIndex,
    hfoldlWithIndex,

    DictF (..),
) where

import           Language.Parser.Ptera.Prelude

import           Type.Membership               (Membership)
import qualified Unsafe.Coerce                 as Unsafe


type T = HFList

data HFList :: (k -> Type) -> [k] -> Type where
    HFNil :: HFList f '[]
    HFCons :: f x -> HFList f xs -> HFList f (x ': xs)


type family Concat (xs1 :: [k]) (xs2 :: [k]) :: [k] where
    Concat '[] xs2 =
        xs2
    Concat (x ': xs1) xs2 =
        x ': Concat xs1 xs2

hconcat :: HFList f xs1 -> HFList f xs2 -> HFList f (Concat xs1 xs2)
hconcat l1 l2 = case l1 of
    HFNil ->
        l2
    HFCons x l1' ->
        HFCons x do hconcat l1' l2

hfoldrWithIndex
    :: forall f r xs
    .  (forall x ys. Membership xs x -> f x -> r ys -> r (x ': ys)) -> r '[]
    -> HFList f xs -> r xs
hfoldrWithIndex f z0 = go 0 where
    go :: Int -> HFList f ys -> r ys
    go m0 = \case
        HFNil ->
            z0
        HFCons y l -> do
            let m1 = m0 + 1
            f
                do unsafeMembership m0
                do y
                do go m1 l

htraverseWithIndex
    :: forall m f g xs
    .  Applicative m
    => (forall x. Membership xs x -> f x -> m (g x))
    -> HFList f xs -> m (HFList g xs)
htraverseWithIndex f = coerce go0 where
    go0 = hfoldrWithIndex go do TraverseHFList do pure HFNil

    go
        :: forall x ys. Membership xs x -> f x
        -> TraverseHFList m g ys -> TraverseHFList m g (x ': ys)
    go m x = \case
        TraverseHFList acc0 ->
            TraverseHFList do HFCons <$> f m x <*> acc0

newtype TraverseHFList m f xs = TraverseHFList (m (HFList f xs))

hmapWithIndex
    :: (forall x. Membership xs x -> f x -> g x)
    -> HFList f xs -> HFList g xs
hmapWithIndex f l = runIdentity
    do htraverseWithIndex
        do \m x -> Identity do f m x
        do l

hfoldMWithIndex :: forall m r f xs
    .  Monad m
    => r -> (forall x. r -> Membership xs x -> f x -> m r)
    -> HFList f xs -> m r
hfoldMWithIndex z0 f = go 0 z0 where
    go :: Int -> r -> HFList f ys -> m r
    go m1 z1 = \case
        HFNil ->
            pure z1
        HFCons y l -> do
            z2 <- f z1
                do unsafeMembership m1
                do y
            let m2 = m1 + 1
            go m2 z2 l

hforMWithIndex
    :: forall m f xs
    .  Applicative m
    => HFList f xs -> (forall x. Membership xs x -> f x -> m ()) -> m ()
hforMWithIndex l0 f = go 0 l0 where
    go :: Int -> HFList f ys -> m ()
    go m1 = \case
        HFNil ->
            pure ()
        HFCons y l -> const
            <$> f
                do unsafeMembership m1
                do y
            <*> go
                do m1 + 1
                l

hfoldlWithIndex
    :: r -> (forall x. r -> Membership xs x -> f x -> r)
    -> HFList f xs -> r
hfoldlWithIndex z0 f = coerce
    do hfoldMWithIndex z0 \z m x -> Identity do f z m x


data DictF :: (k -> Constraint) -> k -> Type where
    DictF :: c x => DictF c x


unsafeMembership :: Int -> Membership xs x
unsafeMembership = Unsafe.unsafeCoerce