module Data.HList.Variant where
import Data.HList.FakePrelude
import Data.HList.Record
import Data.HList.HList
import Data.HList.HListPrelude
import Data.HList.HOccurs()
import Data.HList.HArray
import Text.ParserCombinators.ReadP hiding (optional)
import Unsafe.Coerce
import GHC.Exts (Constraint)
import Data.Semigroup (Semigroup( .. ))
import Data.Data
import Control.Applicative
import LensDefs
import Control.Monad
data Variant (vs :: [*]) = Variant !Int Any
#if __GLASGOW_HASKELL__ > 707
type role Variant representational
#endif
unsafeMkVariant :: Int
-> v
-> Variant vs
unsafeMkVariant n a = Variant n (unsafeCoerce a)
unsafeCastVariant :: Variant v -> Variant v'
unsafeCastVariant (Variant n e) = Variant n e
castVariant :: (RecordValuesR v ~ RecordValuesR v',
SameLength v v') => Variant v -> Variant v'
castVariant = unsafeCastVariant
instance Relabeled Variant where
relabeled = iso castVariant castVariant
unsafeUnVariant :: Variant v -> e
unsafeUnVariant (Variant _ e) = unsafeCoerce e
unsafeEmptyVariant :: Variant '[]
unsafeEmptyVariant = unsafeMkVariant 0 ()
class HasField x (Variant vs) (Maybe v) =>
MkVariant x v vs | x vs -> v where
mkVariant :: Label x
-> v
-> proxy vs
-> Variant vs
mkVariant1 l v = l .=. Just v .*. unsafeEmptyVariant
instance (HFindLabel x vs n,
HNat2Integral n,
HasField x (Variant vs) (Maybe v)) =>
MkVariant x v vs where
mkVariant _x y _p = unsafeMkVariant (hNat2Integral (Proxy :: Proxy n)) y
instance (HasField x (Record vs) a,
HFindLabel x vs n,
HNat2Integral n)
=> HasField x (Variant vs) (Maybe a) where
hLookupByLabel _x (Variant n d)
| hNat2Integral (Proxy :: Proxy n) == n = Just (unsafeCoerce d)
| otherwise = Nothing
splitVariant1 :: Variant (Tagged s x ': xs) -> Either x (Variant xs)
splitVariant1 (Variant 0 x) = Left (unsafeCoerce x)
splitVariant1 (Variant n x) = Right (Variant (n1) x)
splitVariant1' :: Variant (x ': xs) -> Either x (Variant xs)
splitVariant1' (Variant 0 x) = Left (unsafeCoerce x)
splitVariant1' (Variant n x) = Right (Variant (n1) x)
extendVariant :: Variant l -> Variant (e ': l)
extendVariant (Variant m e) = Variant (m+1) e
class (SameLength s t, SameLabels s t)
=> HPrism x s t a b
| x s -> a, x t -> b,
x s b -> t, x t a -> s
where
hPrism :: (Choice p, Applicative f)
=> Label x -> p a (f b) -> p (Variant s) (f (Variant t))
instance (
MkVariant x b t,
HasField x (Variant s) (Maybe a),
SameLength s t,
SameLabels s t,
H2ProjectByLabels '[Label x] s si so,
H2ProjectByLabels '[Label x] t ti to,
so ~ to,
HUpdateAtLabel Variant x b s t,
HUpdateAtLabel Variant x a t s
) => HPrism x s t a b where
hPrism x = prism (\b -> mkVariant x b Proxy)
(\s -> case hLookupByLabel x s of
Just a -> Right a
Nothing -> Left (unsafeCastVariant s :: Variant t))
instance (ShowVariant vs) => Show (Variant vs) where
showsPrec _ v = ("V{"++) . showVariant v . ('}':)
class ShowVariant vs where
showVariant :: Variant vs -> ShowS
instance (ShowLabel l, Show v, ShowVariant (w ': ws))
=> ShowVariant (Tagged l v ': w ': ws) where
showVariant vs = case splitVariant1 vs of
Left v -> \rest -> showLabel l ++ "=" ++ show v ++ rest
Right wws -> showVariant wws
where l = Label :: Label l
instance (ShowLabel l, Show v, lv ~ Tagged l v) => ShowVariant '[lv] where
showVariant vs = case splitVariant1 vs of
Left v -> \rest -> showLabel l ++ "=" ++ show v ++ rest
Right _ -> error "invalid variant"
where l = Label :: Label l
instance ReadVariant v => Read (Variant v) where
readsPrec _ = readP_to_S $ do
_ <- string "V{"
r <- readVariant
_ <- string "}"
return r
class ReadVariant vs where
readVariant :: ReadP (Variant vs)
instance ReadVariant '[] where
readVariant = return unsafeEmptyVariant
instance (ShowLabel l, Read v, ReadVariant vs,
HOccursNot (Label l) (LabelsOf vs))
=> ReadVariant (Tagged l v ': vs) where
readVariant = do
mlv <- optional lv
case mlv of
Nothing -> do
rest <- readVariant
return (l .=. mlv .*. rest)
Just e -> do
return (mkVariant l e p)
where
lv = do
_ <- string (showLabel l)
_ <- string "="
readS_to_P reads
l = Label :: Label l
p = Proxy :: Proxy (Tagged l v ': vs)
instance (Typeable (Variant v), GfoldlVariant v v,
GunfoldVariant v v,
VariantConstrs v)
=> Data (Variant v) where
gfoldl = gfoldlVariant
gunfold k z c = gunfoldVariant (\con -> k (z con)) (Proxy :: Proxy v) (constrIndex c 1)
toConstr v@(Variant n _) = case drop n (variantConstrs (dataTypeOf v) v) of
c : _ -> c
_ -> error "Data.HList.Variant.toConstr impossible"
dataTypeOf x = let self = mkDataType (show (typeOf x)) (variantConstrs self x)
in self
class VariantConstrs (xs :: [*]) where
variantConstrs :: DataType -> proxy xs -> [Constr]
instance VariantConstrs '[] where
variantConstrs _ _ = []
instance (ShowLabel l, VariantConstrs xs) => VariantConstrs (Tagged l e ': xs) where
variantConstrs dt _ = mkConstr dt (showLabel (Label :: Label l)) [] Prefix :
variantConstrs dt (Proxy :: Proxy xs)
class GunfoldVariant (es :: [*]) v where
gunfoldVariant ::
(forall b. Data b => (b -> Variant v) -> c (Variant v))
-> Proxy es
-> Int
-> c (Variant v)
instance (MkVariant l e v, Data e) => GunfoldVariant '[Tagged l e] v where
gunfoldVariant f _ _ = f (\e -> mkVariant (Label :: Label l) (e :: e) Proxy)
instance (MkVariant l e v, Data e,
GunfoldVariant (b ': bs) v) => GunfoldVariant (Tagged l e ': b ': bs) v where
gunfoldVariant f _ 0 = f (\e -> mkVariant (Label :: Label l) (e :: e) Proxy)
gunfoldVariant f _ n = gunfoldVariant f (Proxy :: Proxy (b ': bs)) (n1)
class GfoldlVariant xs xs' where
gfoldlVariant ::
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> Variant xs -> c (Variant xs')
instance (a ~ Tagged l v, MkVariant l v r, Data v,
GfoldlVariant (b ': c) r)
=> GfoldlVariant (a ': b ': c) r where
gfoldlVariant k z xxs = case splitVariant1 xxs of
Right xs -> gfoldlVariant k z xs
Left x ->
let mkV e = mkVariant (Label :: Label l) e Proxy
in z mkV `k` x
instance (Unvariant '[a] v, a ~ Tagged l v, Data v,
MkVariant l v b) => GfoldlVariant '[a] b where
gfoldlVariant k z xxs = z mkV `k` unvariant xxs
where mkV e = mkVariant (Label :: Label l) e Proxy
newtype HMapV f = HMapV f
hMapV f v = applyAB (HMapV f) v
hMapOutV :: forall x y z f. (SameLength x y,
HMapAux Variant (HFmap f) x y,
Unvariant y z,
HMapOutV_gety x z ~ y
) => f -> Variant x -> z
hMapOutV f v = unvariant (hMapV f v :: Variant y)
type family HMapOutV_gety (x :: [*]) (z :: *) :: [*]
type instance HMapOutV_gety (Tagged s x ': xs) z = Tagged s z ': HMapOutV_gety xs z
type instance HMapOutV_gety '[] z = '[]
instance (vx ~ Variant x,
vy ~ Variant y,
HMapAux Variant (HFmap f) x y,
SameLength x y)
=> ApplyAB (HMapV f) vx vy where
applyAB (HMapV f) x = hMapAux (HFmap f) x
instance (ApplyAB f te te') => HMapAux Variant f '[te] '[te'] where
hMapAux f v = case splitVariant1' v of
Left te -> unsafeMkVariant 0 (applyAB f te :: te')
Right _ -> error "HMapVAux: variant invariant broken"
instance (ApplyAB f te te',
HMapCxt Variant f (l ': ls) (l' ': ls'))
=> HMapAux Variant f (te ': l ': ls) (te' ': l' ': ls') where
hMapAux f v = case splitVariant1' v of
Left te -> unsafeMkVariant 0 (applyAB f te :: te')
Right es -> extendVariant (hMapAux f es)
instance
(HUpdateVariantAtLabelCxt l e v v' n _e) =>
HUpdateAtLabel Variant l e v v' where
hUpdateAtLabel l e v = case hLookupByLabel l v of
Just _e -> mkVariant l e (Proxy :: Proxy v')
Nothing -> unsafeCastVariant v
type HUpdateVariantAtLabelCxt l e v v' n _e =
(HFindLabel l v n,
HFindLabel l v' n,
HUpdateAtHNatR n (Tagged l e) v ~ v',
HasField l (Variant v) (Maybe _e),
HasField l (Record v') e,
MkVariant l e v')
instance (le ~ Tagged l (Maybe e), HOccursNot (Label l) (LabelsOf v)) =>
HExtend le (Variant v) where
type HExtendR le (Variant v) = Variant (UnMaybe le ': v)
Tagged (Just e) .*. _ = unsafeMkVariant 0 e
Tagged Nothing .*. (Variant n e) = Variant (n+1) e
type family UnMaybe le
type instance UnMaybe (Tagged l (Maybe e)) = Tagged l e
type instance UnMaybe (Maybe e) = e
class HAllEqVal (x :: [*]) (b :: Bool) | x -> b
instance HAllEqVal '[] True
instance HAllEqVal '[x] True
instance (HEq a a' b,
HAllEqVal (Tagged t a' ': xs) b2,
HAnd b b2 ~ b3) =>
HAllEqVal (Tagged s a ': Tagged t a' ': xs) b3
class HAllEqVal' (x :: [*])
instance HAllEqVal' '[]
instance HAllEqVal' '[x]
instance (HAllEqVal' (ta ': xs),
a' ~ a,
ta ~ Tagged t a,
ta' ~ Tagged t' a')
=> HAllEqVal' (ta' ': ta ': xs)
class Unvariant' v e | v -> e where
unvariant' :: Variant v -> e
instance (HAllEqVal' (Tagged () e ': v), Unvariant v e) =>
Unvariant' v e where
unvariant' = unvariant
class Unvariant v e | v -> e where
unvariant :: Variant v -> e
instance (Unvariant1 b v e,
HAllEqVal v b,
HAllEqVal (Tagged () e ': v) b)
=> Unvariant v e where
unvariant = unvariant1 (Proxy :: Proxy b)
class Unvariant1 b v e | b v -> e where
unvariant1 :: Proxy b -> Variant v -> e
instance (v ~ Tagged t1 e)
=> Unvariant1 True (v ': vs) e where
unvariant1 _ = unsafeUnVariant
data UnvariantTypeMismatch (vs :: [*])
instance Fail (UnvariantTypeMismatch (v ': vs))
=> Unvariant1 False (v ': vs) (UnvariantTypeMismatch (v ': vs)) where
unvariant1 _ = error "Data.HList.Variant.Unvariant1 Fail must have no instances"
instance Fail "Unvariant applied to empty variant"
=> Unvariant1 b '[] (Proxy "Unvariant applied to empty variant") where
unvariant1 _ = error "Data.HList.Variant.Unvariant1 Fail must have no instances"
unvarianted :: (Unvariant' s a,
Unvariant' t b,
SameLabels s t,
SameLength s t,
Functor f) =>
(a -> f b) -> Variant s -> f (Variant t)
unvarianted f v@(Variant n _) = fmap (\e' -> unsafeMkVariant n e')
(f (unvariant' v))
unvarianted' x = simple (unvarianted x)
class ZipVariant x y xy | x y -> xy, xy -> x y where
zipVariant :: Variant x -> Variant y -> Maybe (Variant xy)
instance ZipVariant '[] '[] '[] where
zipVariant _ _ = Nothing
instance (tx ~ Tagged t x,
ty ~ Tagged t y,
txy ~ Tagged t (x,y),
ZipVariant xs ys zs,
MkVariant t (x,y) (txy ': zs))
=> ZipVariant (tx ': xs) (ty ': ys) (txy ': zs) where
zipVariant x y = case (splitVariant1 x, splitVariant1 y) of
(Left x', Left y') -> Just (mkVariant (Label :: Label t) (x',y') Proxy)
(Right x', Right y') -> extendVariant <$> zipVariant x' y'
_ -> Nothing
instance (HUnzip Variant (x2 ': xs) (y2 ': ys) (xy2 ': xys),
SameLength xs ys,
SameLength ys xys,
tx ~ Tagged t x,
ty ~ Tagged t y,
txy ~ Tagged t (x,y))
=> HUnzip Variant (tx ': x2 ': xs) (ty ': y2 ': ys) (txy ': xy2 ': xys) where
hUnzip xy = case splitVariant1 xy of
Left (x,y) -> (mkVariant (Label :: Label t) x Proxy,
mkVariant (Label :: Label t) y Proxy)
Right xy' | (x,y) <- hUnzip xy' ->
(extendVariant x,
extendVariant y)
instance (Unvariant '[txy] txy,
tx ~ Tagged t x,
ty ~ Tagged t y,
txy ~ Tagged t (x,y))
=> HUnzip Variant '[tx] '[ty] '[txy] where
hUnzip xy | Tagged (x,y) <- unvariant xy =
(mkVariant1 Label x, mkVariant1 Label y)
class (SameLength v v',
SameLabels v v') => ZipVR fs v v' | fs v -> v' where
zipVR_ :: Record fs -> Variant v -> Variant v'
instance (lv ~ Tagged l v,
lv' ~ Tagged l v',
HMemberM (Label l) (LabelsOf fs) b,
HasFieldM l (Record fs) f,
DemoteMaybe (v -> v) f ~ (v -> v'),
MkVariant l v' (lv' ': rs),
ZipVR fs vs rs) =>
ZipVR fs (lv ': vs) (lv' ': rs) where
zipVR_ r lvs = case splitVariant1 lvs of
Left v | v' <- hLookupByLabelM l r (id :: v -> v) v -> mkVariant l v' Proxy
Right vs -> extendVariant $ zipVR_ r vs
where l = Label :: Label l
instance ZipVR fs '[] '[] where
zipVR_ _ x = x
zipVR :: (SameLabels fs v, SameLength fs v, ZipVR fs v v',
ZipVRCxt fs v v')
=> Record fs -> Variant v -> Variant v'
zipVR = zipVR_
type family ZipVRCxt (fs :: [*]) (xs :: [*]) (ys :: [*]) :: Constraint
type instance ZipVRCxt (Tagged s f ': fs) (Tagged s x ': xs) (Tagged s y ': ys) =
(f ~ (x -> y), ZipVRCxt fs xs ys)
type instance ZipVRCxt '[] '[] '[] = ()
instance Eq (Variant '[]) where
_ == _ = True
instance (Eq (Variant xs), Eq x) => Eq (Variant (x ': xs)) where
v == v' = case (splitVariant1' v, splitVariant1' v') of
(Left l, Left r) -> l == r
(Right l, Right r) -> l == r
_ -> False
eqVariant v v' = maybe False (hMapOutV UncurryEq) $ zipVariant v v'
data UncurryEq = UncurryEq
instance (ee ~ (e,e), Eq e, bool ~ Bool) =>
ApplyAB UncurryEq ee bool where
applyAB _ (e,e') = e == e'
instance Ord (Variant '[]) where
compare _ _ = EQ
instance (Ord x, Ord (Variant xs)) => Ord (Variant (x ': xs)) where
compare a b = compare (splitVariant1' a) (splitVariant1' b)
instance (Bounded x, Bounded z,
HRevAppR (Tagged s x ': xs) '[] ~ (Tagged t z ': sx),
MkVariant t z (Tagged s x ': xs))
=> Bounded (Variant (Tagged s x ': xs)) where
minBound = mkVariant (Label :: Label s) (minBound :: x) Proxy
maxBound = mkVariant (Label :: Label t) (maxBound :: z) Proxy
instance (Enum x, Bounded x, Enum (Variant (y ': z))) => Enum (Variant (Tagged s x ': y ': z)) where
fromEnum v = case splitVariant1 v of
Left x -> fromEnum x
Right yz -> 1 + fromEnum (maxBound :: Tagged s x) + fromEnum yz
toEnum n
| m >= n = mkVariant (Label :: Label s) (toEnum n) Proxy
| otherwise = extendVariant $ toEnum (n m 1)
where m = fromEnum (maxBound :: Tagged s x)
instance Enum x => Enum (Variant '[Tagged s x]) where
fromEnum v = case splitVariant1 v of
Left x -> fromEnum x
_ -> error "Data.HList.Variant fromEnum impossible"
toEnum n = mkVariant (Label :: Label s) (toEnum n) Proxy
instance (Unvariant '[Tagged t x] x, Semigroup x) => Semigroup (Variant '[Tagged t x]) where
a <> b = case (unvariant a, unvariant b) of
(l, r) -> mkVariant (Label :: Label t) (l <> r) Proxy
instance (Semigroup x, Semigroup (Variant (a ': b))) => Semigroup (Variant (Tagged t x ': a ': b)) where
a <> b = case (splitVariant1 a, splitVariant1 b) of
(Left l, Left r) -> mkVariant (Label :: Label t) (l <> r) Proxy
(Left l, _) -> mkVariant (Label :: Label t) l Proxy
(_, Left r) -> mkVariant (Label :: Label t) r Proxy
(Right l, Right r) -> extendVariant $ l <> r
instance (Unvariant '[Tagged t x] x, Monoid x) => Monoid (Variant '[Tagged t x]) where
mempty = mkVariant (Label :: Label t) mempty Proxy
mappend a b = case (unvariant a, unvariant b) of
(l, r) -> mkVariant (Label :: Label t) (mappend l r) Proxy
instance (Monoid x, Monoid (Variant (a ': b))) => Monoid (Variant (Tagged t x ': a ': b)) where
mempty = extendVariant mempty
mappend a b = case (splitVariant1 a, splitVariant1 b) of
(Left l, Left r) -> mkVariant (Label :: Label t) (mappend l r) Proxy
(Left l, _) -> mkVariant (Label :: Label t) l Proxy
(_, Left r) -> mkVariant (Label :: Label t) r Proxy
(Right l, Right r) -> extendVariant $ mappend l r
class ProjectVariant x y where
projectVariant :: Variant x -> Maybe (Variant y)
instance (ProjectVariant x ys,
HasField t (Variant x) (Maybe y),
HOccursNot (Label t) (LabelsOf ys),
ty ~ Tagged t y)
=> ProjectVariant x (ty ': ys) where
projectVariant x = y `mplus` ys
where t = Label :: Label t
y = (\v -> mkVariant t v Proxy) <$> x .!. t
ys = (mty .*.) <$> (projectVariant x :: Maybe (Variant ys))
mty = Tagged Nothing :: Tagged t (Maybe y)
instance ProjectVariant x '[] where
projectVariant _ = Nothing
class HAllTaggedLV y => ProjectExtendVariant x y where
projectExtendVariant :: Variant x -> Maybe (Variant y)
instance HAllTaggedLV y => ProjectExtendVariant '[] y where
projectExtendVariant _ = Nothing
instance (lv ~ Tagged l v,
HMemberM lv y inY,
ProjectExtendVariant' inY lv y,
ProjectExtendVariant xs y
) => ProjectExtendVariant (lv ': xs) y where
projectExtendVariant v = case splitVariant1' v of
Left lv -> projectExtendVariant' (Proxy :: Proxy inY) lv
Right v' -> projectExtendVariant v'
class ProjectExtendVariant' (inY :: Maybe [*]) lv (y :: [*]) where
projectExtendVariant' :: Proxy inY -> lv -> Maybe (Variant y)
instance ProjectExtendVariant' Nothing lv y where
projectExtendVariant' _ _ = Nothing
instance (MkVariant l v y, lv ~ Tagged l v) => ProjectExtendVariant' (Just t) lv y where
projectExtendVariant' _ (Tagged v) = Just (mkVariant (Label :: Label l) v Proxy)
class (ProjectVariant x yin,
ProjectVariant x yout) => SplitVariant x yin yout where
splitVariant :: Variant x -> Either (Variant yin) (Variant yout)
instance
(
ProjectVariant x yin,
ProjectVariant x yout,
H2ProjectByLabels (LabelsOf yin) x xi xo,
HRearrange (LabelsOf yin) xi yin,
HRearrange (LabelsOf yout) xo yout,
HLeftUnion xi xo xixo,
HRearrange (LabelsOf x) xixo x,
HAllTaggedLV x, HAllTaggedLV yin, HAllTaggedLV yout) =>
SplitVariant x yin yout where
splitVariant x = case (projectVariant x, projectVariant x) of
(Nothing, Just yout) -> Right yout
(Just yin, Nothing) -> Left yin
_ -> error "Data.HList.Variant:splitVariant impossible"
class (HAllTaggedLV y, HAllTaggedLV x) => ExtendsVariant x y where
extendsVariant :: Variant x -> Variant y
instance (MkVariant l e y, le ~ Tagged l e,
ExtendsVariant (b ': bs) y) => ExtendsVariant (le ': b ': bs) y where
extendsVariant v = case splitVariant1 v of
Left e -> mkVariant (Label :: Label l) (e :: e) Proxy
Right vs -> extendsVariant vs
instance (HAllTaggedLV x, Unvariant '[le] e, MkVariant l e x,
le ~ Tagged l e) => ExtendsVariant '[le] x where
extendsVariant v = mkVariant (Label :: Label l) (unvariant v) Proxy
rearrangeVariant :: (SameLength v v', ExtendsVariant v v')
=> Variant v -> Variant v'
rearrangeVariant v = extendsVariant v
instance (SameLength s a, ExtendsVariant s a,
SameLength b t, ExtendsVariant b t) => Rearranged Variant s t a b
where
rearranged = iso rearrangeVariant rearrangeVariant
hMaybied x = prism variantToHMaybied
(\s -> case hMaybiedToVariants s of
[a] -> Right a
_ -> Left (hMapR HCastF s))
x
data HCastF = HCastF
instance (mx ~ Maybe x,
my ~ Maybe y,
HCast y x) =>
ApplyAB HCastF mx my where
applyAB _ x = hCast =<< x
hMaybied' x = simple (hMaybied (simple x))
class VariantToHMaybied v r | v -> r, r -> v where
variantToHMaybied :: Variant v -> Record r
instance VariantToHMaybied '[] '[] where
variantToHMaybied _ = emptyRecord
instance (VariantToHMaybied v r,
HReplicateF nr ConstTaggedNothing () r,
tx ~ Tagged t x,
tmx ~ Tagged t (Maybe x))
=> VariantToHMaybied (tx ': v) (tmx ': r) where
variantToHMaybied v = case splitVariant1 v of
Left x -> Record
$ HCons (Tagged (Just x))
$ hReplicateF Proxy ConstTaggedNothing ()
Right rest ->
case variantToHMaybied rest of
Record a -> Record $ (Tagged Nothing :: Tagged t (Maybe x)) `HCons` a
data ConstTaggedNothing = ConstTaggedNothing
instance (y ~ Tagged t (Maybe e)) => ApplyAB ConstTaggedNothing x y where
applyAB _ _ = Tagged Nothing
hMaybiedToVariants ::
(HFoldr HMaybiedToVariantFs [Variant '[]] r [Variant v],
VariantToHMaybied v r
) => Record r -> [Variant v]
hMaybiedToVariants (Record r) = hFoldr HMaybiedToVariantFs ([] :: [Variant '[]]) r
data HMaybiedToVariantFs = HMaybiedToVariantFs
instance (x ~ (Tagged t (Maybe e), [Variant v]),
y ~ [Variant (Tagged t e ': v)],
MkVariant t e (Tagged t e ': v))
=> ApplyAB HMaybiedToVariantFs x y where
applyAB _ (Tagged me, v) = case me of
Just e -> mkVariant (Label :: Label t) e Proxy : map extendVariant v
_ -> fmap extendVariant v