{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE PolyKinds #-}
module Haskus.Utils.VariantF
( VariantF (..)
, ApplyAll
, pattern FV
, appendVariantF
, prependVariantF
, toVariantFHead
, toVariantFTail
, popVariantFHead
, variantFToValue
, MapVariantF
, mapVariantF
, PopVariantF
, popVariantF
, LiftVariantF
, liftVariantF
, SplitVariantF
, splitVariantF
, variantFToCont
, variantFToContM
, contToVariantF
, contToVariantFM
, BottomUpF
, BottomUp (..)
, BottomUpOrig (..)
, BottomUpOrigF
, TopDownStop (..)
, TopDownStopF
, NoConstraint
, module Haskus.Utils.Functor
)
where
import Haskus.Utils.Variant
import Haskus.Utils.Functor
import Haskus.Utils.Types.List
import Haskus.Utils.Types.Constraint
import Haskus.Utils.ContFlow
import Haskus.Utils.Types
import Data.Bifunctor
import Control.DeepSeq
newtype VariantF (xs :: [t -> *]) (e :: t)
= VariantF (V (ApplyAll e xs))
type family ApplyAll (e :: t) (xs :: [t -> k]) :: [k] where
ApplyAll e '[] = '[]
ApplyAll e (f ': fs) = f e ': ApplyAll e fs
type instance Base (VariantF xs a) = VariantF xs
instance
( Eq1 (VariantF xs)
, ConstraintAll1 Eq1 xs
, Eq e
) => Eq (VariantF xs e)
where
(==) = eq1
instance
( Ord1 (VariantF xs)
, ConstraintAll1 Ord1 xs
, ConstraintAll1 Eq1 xs
, Ord e
) => Ord (VariantF xs e)
where
compare = compare1
instance Eq1 (VariantF '[]) where
liftEq = undefined
instance
( Eq1 f
, Eq1 (VariantF fs)
) => Eq1 (VariantF (f:fs)) where
liftEq cmp x y = case (popVariantFHead x, popVariantFHead y) of
(Right a, Right b) -> liftEq cmp a b
(Left a, Left b) -> liftEq cmp a b
_ -> False
instance Ord1 (VariantF '[]) where
liftCompare = undefined
instance
( Ord1 f
, Ord1 (VariantF fs)
) => Ord1 (VariantF (f:fs)) where
liftCompare cmp x@(VariantF v1) y@(VariantF v2) =
case (popVariantFHead x, popVariantFHead y) of
(Right a, Right b) -> liftCompare cmp a b
(Left a, Left b) -> liftCompare cmp a b
_ -> compare (variantIndex v1) (variantIndex v2)
instance Show1 (VariantF '[]) where
liftShowsPrec = undefined
instance
( Show1 f
, Show1 (VariantF fs)
) => Show1 (VariantF (f:fs)) where
liftShowsPrec shw shwl p x = case popVariantFHead x of
Right a -> liftShowsPrec shw shwl p a
Left a -> liftShowsPrec shw shwl p a
instance
( Show1 (VariantF xs)
, ConstraintAll1 Show1 xs
, Show e
) => Show (VariantF xs e)
where
showsPrec = showsPrec1
instance Functor (VariantF '[]) where
fmap _ = undefined
instance (Functor (VariantF fs), Functor f) => Functor (VariantF (f ': fs)) where
fmap f (VariantF v) = case popVariantHead v of
Right x -> toVariantFHead (fmap f x)
Left xs -> toVariantFTail (fmap f (VariantF xs))
pattern FV :: forall c cs e. c :< (ApplyAll e cs) => c -> VariantF cs e
pattern FV x = VariantF (V x)
variantFToValue :: VariantF '[f] e -> f e
variantFToValue (VariantF v) = variantToValue v
appendVariantF :: forall (ys :: [* -> *]) (xs :: [* -> *]) e.
( ApplyAll e (Concat xs ys) ~ Concat (ApplyAll e xs) (ApplyAll e ys)
) => VariantF xs e -> VariantF (Concat xs ys) e
appendVariantF (VariantF v) = VariantF (appendVariant @(ApplyAll e ys) v)
prependVariantF :: forall (xs :: [* -> *]) (ys :: [* -> *]) e.
( ApplyAll e (Concat xs ys) ~ Concat (ApplyAll e xs) (ApplyAll e ys)
, KnownNat (Length (ApplyAll e xs))
) => VariantF ys e -> VariantF (Concat xs ys) e
prependVariantF (VariantF v) = VariantF (prependVariant @(ApplyAll e xs) v)
toVariantFHead :: forall x xs e. x e -> VariantF (x ': xs) e
{-# INLINABLE toVariantFHead #-}
toVariantFHead v = VariantF (toVariantHead @(x e) @(ApplyAll e xs) v)
toVariantFTail :: forall x xs e. VariantF xs e -> VariantF (x ': xs) e
{-# INLINABLE toVariantFTail #-}
toVariantFTail (VariantF v) = VariantF (toVariantTail @(x e) @(ApplyAll e xs) v)
popVariantFHead :: forall x xs e. VariantF (x ': xs) e -> Either (VariantF xs e) (x e)
{-# INLINABLE popVariantFHead #-}
popVariantFHead (VariantF v) = case popVariantHead v of
Right x -> Right x
Left xs -> Left (VariantF xs)
type PopVariantF x xs e =
( x e :< ApplyAll e xs
, Remove (x e) (ApplyAll e xs) ~ ApplyAll e (Remove x xs)
)
popVariantF :: forall x xs e.
( PopVariantF x xs e
) => VariantF xs e -> Either (VariantF (Remove x xs) e) (x e)
{-# INLINABLE popVariantF #-}
popVariantF (VariantF v) = case popVariant v of
Right x -> Right x
Left xs -> Left (VariantF xs)
type MapVariantF a b cs ds e =
( MapVariant (a e) (b e) (ApplyAll e cs)
, ds ~ ReplaceNS (IndexesOf a cs) b cs
, ApplyAll e ds ~ ReplaceNS (IndexesOf (a e) (ApplyAll e cs)) (b e) (ApplyAll e cs)
)
mapVariantF :: forall a b cs ds e.
( MapVariantF a b cs ds e
) => (a e -> b e) -> VariantF cs e -> VariantF ds e
mapVariantF f (VariantF v) = VariantF (mapVariant @(a e) @(b e) @(ApplyAll e cs) f v)
type LiftVariantF xs ys e =
( LiftVariant (ApplyAll e xs) (ApplyAll e ys)
)
liftVariantF :: forall as bs e.
( LiftVariantF as bs e
) => VariantF as e -> VariantF bs e
liftVariantF (VariantF v) = VariantF (liftVariant' v)
type SplitVariantF as xs e =
( Complement (ApplyAll e xs) (ApplyAll e as) ~ ApplyAll e (Complement xs as)
, SplitVariant (ApplyAll e as) (ApplyAll e (Complement xs as)) (ApplyAll e xs)
)
splitVariantF :: forall as xs e.
( SplitVariantF as xs e
) => VariantF xs e
-> Either (VariantF (Complement xs as) e) (VariantF as e)
splitVariantF (VariantF v) = bimap VariantF VariantF (splitVariant v)
variantFToCont :: ContVariant (ApplyAll e xs)
=> VariantF xs e -> ContFlow (ApplyAll e xs) r
variantFToCont (VariantF v) = variantToCont v
variantFToContM ::
( ContVariant (ApplyAll e xs)
, Monad m
) => m (VariantF xs e) -> ContFlow (ApplyAll e xs) (m r)
variantFToContM f = variantToContM (unvariantF <$> f)
where
unvariantF (VariantF v) = v
contToVariantF :: forall xs e.
( ContVariant (ApplyAll e xs)
) => ContFlow (ApplyAll e xs) (V (ApplyAll e xs)) -> VariantF xs e
contToVariantF c = VariantF (contToVariant c)
contToVariantFM :: forall xs e m.
( ContVariant (ApplyAll e xs)
, Monad m
) => ContFlow (ApplyAll e xs) (m (V (ApplyAll e xs))) -> m (VariantF xs e)
contToVariantFM f = VariantF <$> contToVariantM f
instance ContVariant (ApplyAll e xs) => MultiCont (VariantF xs e) where
type MultiContTypes (VariantF xs e) = ApplyAll e xs
toCont = variantFToCont
toContM = variantFToContM
deriving newtype instance (NFData (V (ApplyAll e xs))) => NFData (VariantF xs e)
type family BottomUpF c fs :: Constraint where
BottomUpF c fs = (Functor (VariantF fs), BottomUp c fs)
class BottomUp c fs where
toBottomUp :: (forall f. c f => f a -> b) -> (VariantF fs a -> b)
instance BottomUp c '[] where
{-# INLINABLE toBottomUp #-}
toBottomUp _f = undefined
instance forall c fs f.
( BottomUp c fs
, c f
) => BottomUp c (f ':fs) where
{-# INLINABLE toBottomUp #-}
toBottomUp f v = case popVariantFHead v of
Right x -> f x
Left xs -> toBottomUp @c f xs
type family BottomUpOrigF c fs :: Constraint where
BottomUpOrigF c fs = (Functor (VariantF fs), BottomUpOrig c fs)
class BottomUpOrig c fs where
toBottomUpOrig :: (forall f. c f => f (t,a) -> b) -> (VariantF fs (t,a) -> b)
instance BottomUpOrig c '[] where
{-# INLINABLE toBottomUpOrig #-}
toBottomUpOrig _f = undefined
instance forall c fs f.
( BottomUpOrig c fs
, c f
) => BottomUpOrig c (f ': fs) where
{-# INLINABLE toBottomUpOrig #-}
toBottomUpOrig f v = case popVariantFHead v of
Right x -> f x
Left xs -> toBottomUpOrig @c f xs
type family TopDownStopF c fs :: Constraint where
TopDownStopF c fs = (Functor (VariantF fs), TopDownStop c fs)
class TopDownStop c fs where
toTopDownStop :: (forall f. c f => TopDownStopT a f) -> TopDownStopT a (VariantF fs)
instance TopDownStop c '[] where
{-# INLINABLE toTopDownStop #-}
toTopDownStop _f = undefined
instance forall c fs f.
( TopDownStop c fs
, Functor f
, c f
) => TopDownStop c (f ':fs) where
{-# INLINABLE toTopDownStop #-}
toTopDownStop f v = case popVariantFHead v of
Right x -> first toVariantFHead (f x)
Left xs -> first (prependVariantF @'[f]) (toTopDownStop @c f xs)