{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Haskus.Utils.EADT
( EADT (..)
, (:<:)
, (:<<:)
, pattern VF
, appendEADT
, liftEADT
, popEADT
, contToEADT
, contToEADTM
, module Haskus.Utils.Functor
, module Haskus.Utils.VariantF
)
where
import Haskus.Utils.VariantF
import Haskus.Utils.Variant
import Haskus.Utils.Functor
import Haskus.Utils.Types.List
import Haskus.Utils.Types.Constraint
import Haskus.Utils.Types
import Haskus.Utils.ContFlow
newtype EADT fs
= EADT (VariantF fs (EADT fs))
type instance Base (EADT fs) = VariantF fs
instance Functor (VariantF fs) => Recursive (EADT fs) where
project (EADT a) = a
instance Functor (VariantF fs) => Corecursive (EADT fs) where
embed = EADT
instance Eq1 (VariantF fs) => Eq (EADT fs) where
EADT a == EADT b = eq1 a b
instance Ord1 (VariantF fs) => Ord (EADT fs) where
compare (EADT a) (EADT b) = compare1 a b
instance Show1 (VariantF fs) => Show (EADT fs) where
showsPrec d (EADT a) =
showParen (d >= 11)
$ showString "EADT "
. showsPrec1 11 a
type family f :<: xs where
f :<: xs = EADTF' f (EADT xs) xs
type family (:<<:) xs ys :: Constraint where
'[] :<<: ys = ()
(x ': xs) :<<: ys = (x :<: ys, xs :<<: ys)
type EADTF' f e cs =
( Member f cs
, Index (IndexOf (f e) (ApplyAll e cs)) (ApplyAll e cs) ~ f e
, PopVariant (f e) (ApplyAll e cs)
, KnownNat (IndexOf (f e) (ApplyAll e cs))
, Remove (f e) (ApplyAll e cs) ~ ApplyAll e (Remove f cs)
)
pattern VF :: forall e f cs.
( e ~ EADT cs
, f :<: cs
) => f (EADT cs) -> EADT cs
pattern VF x = EADT (VariantF (VSilent x))
appendEADT :: forall ys xs zs.
( zs ~ Concat xs ys
, ApplyAll (EADT zs) zs ~ Concat (ApplyAll (EADT zs) xs) (ApplyAll (EADT zs) ys)
, Functor (VariantF xs)
) => EADT xs -> EADT zs
appendEADT (EADT v) = EADT (appendVariantF @ys (fmap (appendEADT @ys) v))
liftEADT :: forall e as bs.
( e ~ EADT bs
, LiftVariantF as bs e
, Functor (VariantF as)
) => EADT as -> EADT bs
liftEADT = cata (EADT . liftVariantF)
popEADT :: forall f xs e.
( f :<: xs
, e ~ EADT xs
, f e :< ApplyAll e xs
) => EADT xs -> Either (VariantF (Remove f xs) (EADT xs)) (f (EADT xs))
popEADT (EADT v) = popVariantF v
instance (Functor (VariantF xs), ContVariant (ApplyAll (EADT xs) xs)) => MultiCont (EADT xs) where
type MultiContTypes (EADT xs) = ApplyAll (EADT xs) xs
toCont (EADT v) = variantFToCont v
toContM f = variantFToContM (project <$> f)
contToEADT ::
( ContVariant (ApplyAll (EADT xs) xs)
) => ContFlow (ApplyAll (EADT xs) xs)
(V (ApplyAll (EADT xs) xs))
-> EADT xs
contToEADT c = EADT (contToVariantF c)
contToEADTM ::
( ContVariant (ApplyAll (EADT xs) xs)
, Monad f
) => ContFlow (ApplyAll (EADT xs) xs)
(f (V (ApplyAll (EADT xs) xs)))
-> f (EADT xs)
contToEADTM f = EADT <$> contToVariantFM f