HList- Heterogeneous lists

Safe HaskellNone




The HList library

See CommonMain#Variant for the public (safe) interface.

The implementation here follows Data.Dynamic, though Typeable is not needed.

See broken/VariantP.hs and broken/VariantOld.hs for different approaches to open sums.


Labels for doctests

>>> import Data.HList.RecordPuns
>>> let x = Label :: Label "x"
>>> let y = Label :: Label "y"
>>> let z = Label :: Label "z"
>>> let _left = Label :: Label "left"
>>> let _right = Label :: Label "right"
>>> :set -XQuasiQuotes -XViewPatterns -XDataKinds
  • - * Creating Variants

It is necessary to specify the order in which the fields occur, using a data type like

>>> let p = Proxy :: Proxy '[Tagged "left" Char, Tagged "right" Int]

Then this argument can be passed into mkVariant

>>> let v = mkVariant _left 'x' p
>>> let w = mkVariant _right 5  p
>>> :t v
v :: Variant '[Tagged "left" Char, Tagged "right" Int]
>>> :t w
w :: Variant '[Tagged "left" Char, Tagged "right" Int]
>>> [v,w]

Alternative: a Record as the Proxy

The type of mkVariant also allows using a Record as the proxy. For example:

>>> :{
let p2 = [pun| left right |] where
            left = 'a'
            right = (4::Int)
>>> let v2 = mkVariant _left 'x' p2
>>> let w2 = mkVariant _right 5  p2
>>> :t v2
v2 :: Variant '[Tagged "left" Char, Tagged "right" Int]
>>> :t w2
w2 :: Variant '[Tagged "left" Char, Tagged "right" Int]
>>> (v2,w2)

A polymorphic Proxy

It is also possible to leave the Char and Int as type variables, and have them inferred.

>>> let p3 = Proxy :: Proxy '[Tagged "left" a, Tagged "right" b]

Using p3 takes some care. The following attempt shows the problem:

>>> :{
let v3' = mkVariant _left 'x' p3
    w3' = mkVariant _right (5::Int) p3
>>> :t v3'
v3' :: Variant '[Tagged "left" Char, Tagged "right" b]
>>> :t w3'
w3' :: Variant '[Tagged "left" a, Tagged "right" Int]

Here each use of p3 does not constrain the type of the other use. In some cases those type variables will be inferred from other constraints, such as when putting the variants into a list

>>> [v3', w3']

In other cases the other tags will be defaulted to (), at least if ExtendedDefaultRules is enabled:

>>> v3'
>>> :set -XNoExtendedDefaultRules
>>> v3'
...No instance for (Show ...) arising from a use of ‘print’

Another way around this issue is to make sure that the proxy is bound in a monomorphic pattern. These are patterns that allow name shadowing.

An example of the case:

>>> :{
let (v3,w3) = case p3 of
              p -> (mkVariant _left 'x' p,
                    mkVariant _right (5 :: Int) p)
>>> :t v3
v3 :: Variant '[Tagged "left" Char, Tagged "right" Int]
>>> :t w3
w3 :: Variant '[Tagged "left" Char, Tagged "right" Int]

data Variant vs Source

Variant vs has an implementation similar to Dynamic, except the contained value is one of the elements of the vs list, rather than being one particular instance of Typeable.

>>> v .!. _right
>>> v .!. _left
Just 'x'

In some cases the pun quasiquote works with variants,

>>> let f [pun| left right |] = (left,right)
>>> f v
(Just 'x',Nothing)
>>> f w
(Nothing,Just 5)
>>> let add1 v = hMapV (Fun succ :: Fun '[Enum] '()) v
>>> f (add1 v)
(Just 'y',Nothing)
>>> f (add1 w)
(Nothing,Just 6)


Variant !Int Any 


Relabeled Variant 
TypeIndexed Variant TIC 
(ExtendsVariant b t, ProjectVariant s a, ProjectExtendVariant s t, HLeftUnion b s bs, HRLabelSet bs, HRearrange (LabelsOf t) bs t) => Projected Variant s t a b
Prism (Variant s) (Variant t) (Variant a) (Variant b)
HUpdateVariantAtLabelCxt k l e v v' n _e => HUpdateAtLabel k Variant l e v v'
hUpdateAtLabel x e' (mkVariant x e proxy) == mkVariant x e' proxy
hUpdateAtLabel y e' (mkVariant x e proxy) == mkVariant x e  proxy
(HPrism k x s t a b, (~) (* -> * -> *) to (->)) => Labelable k x Variant s t a b

make a Prism (Variant s) (Variant t) a b

(HasField k x (Record vs) a, HFindLabel k x vs n, HNat2Integral n) => HasField k x (Variant vs) (Maybe a) 
(ApplyAB f te te', HMapCxt Variant f ((:) * l ls) ((:) * l' ls')) => HMapAux Variant f ((:) * te ((:) * l ls)) ((:) * te' ((:) * l' ls')) 
ApplyAB f te te' => HMapAux Variant f ((:) * te ([] *)) ((:) * te' ([] *)) 
((~) * le (Tagged k l (Maybe e)), HOccursNot * (Label k l) (LabelsOf v)) => HExtend le (Variant v)

Extension for Variants prefers the first value

(l .=. Nothing) .*. v = v
(l .=. Just e)  .*. _ = mkVariant l e Proxy
(Unvariant ((:) * txy ([] *)) txy, (~) * tx (Tagged k t x), (~) * ty (Tagged k t y), (~) * txy (Tagged k t (x, y))) => HUnzip Variant ((:) * tx ([] *)) ((:) * ty ([] *)) ((:) * txy ([] *)) 
(HUnzip Variant ((:) * x2 xs) ((:) * y2 ys) ((:) * xy2 xys), (~) * tx (Tagged k t x), (~) * ty (Tagged k t y), (~) * txy (Tagged k t (x, y))) => HUnzip Variant ((:) * tx ((:) * x2 xs)) ((:) * ty ((:) * y2 ys)) ((:) * txy ((:) * xy2 xys)) 
(Bounded x, Bounded z, (~) [*] (HRevAppR * ((:) * (Tagged k1 s x) xs) ([] *)) ((:) * (Tagged k t z) sx), MkVariant k t z ((:) * (Tagged k1 s x) xs)) => Bounded (Variant ((:) * (Tagged k s x) xs)) 
Enum x => Enum (Variant ((:) * (Tagged k s x) ([] *)))

While the instances could be written Enum (Variant '[]) Eq/Ord which cannot produce values, so they have instances for empty variants (unsafeEmptyVariant). Enum can produce values, so it is better that fromEnum 0 :: Variant '[] fails with No instance for Enum (Variant '[]) than producing an invalid variant.

(Enum x, Bounded x, Enum (Variant ((:) * y z))) => Enum (Variant ((:) * (Tagged k s x) ((:) * y z)))
>>> let t = minBound :: Variant '[Tagged "x" Bool, Tagged "y" Bool]
>>> [t .. maxBound]
Odd behavior
There are some arguments that this instance should not exist.

The last type in the Variant does not need to be Bounded. This means that enumFrom behaves a bit unexpectedly:

>>> [False .. ]
>>> [t .. ]
[V{x=False},V{x=True},V{y=False},V{y=True},V{y=*** Exception: Prelude.Enum.Bool.toEnum: bad argument

This is a "feature" because it allows an Enum (Variant '[Tagged "a" Bool, Tagged "n" Integer])

Another difficult choice is that the lower bound is fromEnum 0 rather than minBound:

>>> take 5 [ minBound :: Variant '[Tagged "b" Bool, Tagged "i" Int] .. ]
(Eq (Variant xs), Eq x) => Eq (Variant ((:) * x xs)) 
Eq (Variant ([] *)) 
(Typeable * (Variant v), GfoldlVariant v v, GunfoldVariant v v, VariantConstrs v) => Data (Variant v) 
(Ord x, Ord (Variant xs)) => Ord (Variant ((:) * x xs)) 
Ord (Variant ([] *)) 
ReadVariant v => Read (Variant v)

A corresponding read instance

ShowVariant vs => Show (Variant vs)

Variants are not opaque

(Monoid x, Monoid (Variant ((:) * a b))) => Monoid (Variant ((:) * (Tagged k t x) ((:) * a b)))

XXX check this mappend is legal

(Unvariant ((:) * (Tagged k t x) ([] *)) x, Monoid x) => Monoid (Variant ((:) * (Tagged k t x) ([] *))) 
(SameLength * * s a, ExtendsVariant s a, SameLength * * b t, ExtendsVariant b t) => Rearranged [*] Variant s t a b 
Typeable ([*] -> *) Variant 
type LabelableTy Variant = LabelablePrism 
type HExtendR le (Variant v) = Variant ((:) * (UnMaybe le) v) 

Unsafe operations

unsafeMkVariant Source


:: Int


-> v 
-> Variant vs 

This is only safe if the n'th element of vs has type Tagged t v

unsafeCastVariant :: Variant v -> Variant v' Source

Safe when (e ~ e') given that

Tagged t e ~ HLookupByHNatR n v
Tagged t' e' ~ HLookupByHNatR n v'

hUpdateAtLabel is the safe version

castVariant :: (RecordValuesR v ~ RecordValuesR v', SameLength v v') => Variant v -> Variant v' Source

in ghc>=7.8, coerce is probably a better choice

unsafeUnVariant :: Variant v -> e Source

private destructor. This is safe only if the value contained actually has type e

unsafeEmptyVariant :: Variant [] Source

This function is unsafe because it can lead to a runtime error when used together with the HExtend instance (.*.)

>>> print $ (Label :: Label "x") .=. (Nothing :: Maybe ()) .*. unsafeEmptyVariant
V{*** Exception: invalid variant

use mkVariant1 instead

Public constructor

class HasField x (Variant vs) (Maybe v) => MkVariant x v vs | x vs -> v where Source


mkVariant Source


:: Label x

the tag

-> v

value to be stored

-> proxy vs

a helper to fix the ordering and types of the potential values that this variant contains. Typically this will be a Proxy, Record or another Variant

-> Variant vs 


(HFindLabel k x vs n, HNat2Integral n, HasField k x (Variant vs) (Maybe v)) => MkVariant k x v vs 

mkVariant1 :: Label k l -> e -> Variant ((:) * (Tagged k l e) ([] *)) Source

Public destructor

hLookupByLabel (synonym .!.)

(.!.)             :: Variant v -> Label x -> Maybe e
hLookupByLabel    :: Label x -> Variant v -> Maybe e

hPrism and hLens' combine this with mkVariant

splitVariant1' :: Variant (x : xs) -> Either x (Variant xs) Source

x ~ Tagged s t


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 Source

Make a Prism (Variant s) (Variant t) a b out of a Label.

See Data.HList.Labelable.hLens' is a more overloaded version.

Few type annotations are necessary because of the restriction that s and t have the same labels in the same order, and to get "t" the "a" in "s" is replaced with "b".


hPrism :: (Choice p, Applicative f) => Label x -> p a (f b) -> p (Variant s) (f (Variant t)) Source


(MkVariant k x b t, HasField k x (Variant s) (Maybe a), SameLength * * s t, SameLabels [*] [*] s t, H2ProjectByLabels ((:) * (Label k x) ([] *)) s si so, H2ProjectByLabels ((:) * (Label k x) ([] *)) t ti to, (~) [*] so to, HUpdateAtLabel k Variant x b s t, HUpdateAtLabel k Variant x a t s) => HPrism k x s t a b 


class ShowVariant vs where Source

helper class for defining the Show instance


(ShowLabel k l, Show v, (~) * lv (Tagged k l v)) => ShowVariant ((:) * lv ([] *)) 
(ShowLabel k l, Show v, ShowVariant ((:) * w ws)) => ShowVariant ((:) * (Tagged k l v) ((:) * w ws)) 


class ReadVariant vs where Source


ReadVariant ([] *) 
(ShowLabel k l, Read v, ReadVariant vs, HOccursNot * (Label k l) (LabelsOf vs)) => ReadVariant ((:) * (Tagged k l v) vs) 


class VariantConstrs xs where Source


variantConstrs :: DataType -> proxy xs -> [Constr] Source


VariantConstrs ([] *) 
(ShowLabel k l, VariantConstrs xs) => VariantConstrs ((:) * (Tagged k l e) xs) 

class GunfoldVariant es v where Source

implementation of gunfold for Variant

In ghci

:set -ddump-deriv -XDeriveDataTypeable
data X a b c = A a | B b | C c deriving (Data,Typeable)

shows that gunfold is defined something like

gunfold k z c = case constrIndex c of
      1 -> k (z Ghci1.A)
      2 -> k (z Ghci1.B)
      _ -> k (z Ghci1.C)

If we instead had

type X a b c = Variant [Tagged "A" a, Tagged "B" b, Tagged "C" c]

Then we could write:

gunfold1 :: (forall b r. Data b => (b -> r) -> c r)
         -> Variant [Tagged "A" a, Tagged "B" b, Tagged "C" c]
gunfold1 f c = case constrIndex c of
      1 -> f mkA
      2 -> f mkB
      _ -> f mkC
  where mkA a = mkVariant (Label :: Label "A") (a :: a) v
        mkB b = mkVariant (Label :: Label "B") (b :: b) v
        mkC c = mkVariant (Label :: Label "C") (c :: c) v
        v = Proxy :: Proxy [Tagged "A" a, Tagged "B" b, Tagged "C" c]

where f = k.z


gunfoldVariant Source


:: (forall b. Data b => (b -> Variant v) -> c (Variant v))
f = k . z
-> Proxy es 
-> Int 
-> c (Variant v) 


(MkVariant k l e v, Data e, GunfoldVariant ((:) * b bs) v) => GunfoldVariant ((:) * (Tagged k l e) ((:) * b bs)) v 
(MkVariant k l e v, Data e) => GunfoldVariant ((:) * (Tagged k l e) ([] *)) v 

class GfoldlVariant xs xs' where Source


gfoldlVariant :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Variant xs -> c (Variant xs') Source

the same as gfoldl, except the variant that is returned can have more possible values (needed to actually implement gfoldl).


(Unvariant ((:) * a ([] *)) v, (~) * a (Tagged k l v), Data v, MkVariant k l v b) => GfoldlVariant ((:) * a ([] *)) b 
((~) * a (Tagged k l v), MkVariant k l v r, Data v, GfoldlVariant ((:) * b c) r) => GfoldlVariant ((:) * a ((:) * b c)) r 


newtype HMapV f Source

Apply a function to all possible elements of the variant


HMapV f 


((~) * vx (Variant x), (~) * vy (Variant y), HMapAux Variant (HFmap f) x y, SameLength * * x y) => ApplyAB (HMapV f) vx vy

apply a function to all values that could be in the variant.

hMapV :: (HMapAux Variant (HFmap f) x y, SameLength' * * y x, SameLength' * * x y) => f -> Variant x -> Variant y Source

shortcut for applyAB . HMapV. hMap is more general

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 Source

hMapOutV f = unvariant . hMapV f, except an ambiguous type variable is resolved by HMapOutV_gety

type family HMapOutV_gety x z :: [*] Source

resolves an ambiguous type in hMapOutV


type HMapOutV_gety ([] *) z = [] * 
type HMapOutV_gety ((:) * (Tagged k s x) xs) z = (:) * (Tagged k s z) (HMapOutV_gety xs z) 

HUpdateAtLabel instance

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') Source

HExtend instance

type family UnMaybe le Source


type UnMaybe (Maybe e) = e

used for HExtend TIP

type UnMaybe (Tagged k l (Maybe e)) = Tagged k l e 

Conversion to an untagged value

class HAllEqVal x b | x -> b Source


HAllEqVal ([] *) True 
HAllEqVal ((:) * x ([] *)) True 
(HEq * a a' b, HAllEqVal ((:) * (Tagged k1 t a') xs) b2, (~) Bool (HAnd b b2) b3) => HAllEqVal ((:) * (Tagged k s a) ((:) * (Tagged k t a') xs)) b3 

class HAllEqVal' x Source


HAllEqVal' ([] *) 
(HAllEqVal' ((:) * ta xs), (~) * a' a, (~) * ta (Tagged k t a), (~) * ta' (Tagged k1 t' a')) => HAllEqVal' ((:) * ta' ((:) * ta xs)) 
HAllEqVal' ((:) * x ([] *)) 

class Unvariant' v e | v -> e where Source

Similar to unvariant, except type variables in v will be made equal to e if possible. That allows the type of Nothing to be inferred as Maybe Char.

>>> unvariant' $ x .=. Nothing .*. mkVariant1 y 'y'

However, this difference leads to more local error messages (Couldn't match type ‘()’ with ‘Char’), rather than the following with unvariant:

     '[Tagged "left" Char, Tagged "right" ()],
     "must have all values equal to ",


unvariant' :: Variant v -> e Source


(HAllEqVal' ((:) * (Tagged * () e) v), Unvariant v e) => Unvariant' v e 

class Unvariant v e | v -> e where Source

Convert a Variant which has all possibilities having the same type into a value of that type. Analogous to either id id.

See also unvariant'


unvariant :: Variant v -> e Source


(Unvariant1 Bool b v e, HAllEqVal v b, HAllEqVal ((:) * (Tagged * () e) v) b) => Unvariant v e 

class Unvariant1 b v e | b v -> e where Source


unvariant1 :: Proxy b -> Variant v -> e Source


Fail Symbol "Unvariant applied to empty variant" => Unvariant1 k b ([] *) (Proxy Symbol "Unvariant applied to empty variant") 
(~) * v (Tagged k t1 e) => Unvariant1 Bool True ((:) * v vs) e 
Fail * (UnvariantTypeMismatch ((:) * v vs)) => Unvariant1 Bool False ((:) * v vs) (UnvariantTypeMismatch ((:) * v vs)) 

data UnvariantTypeMismatch vs Source


Fail * (UnvariantTypeMismatch ((:) * v vs)) => Unvariant1 Bool False ((:) * v vs) (UnvariantTypeMismatch ((:) * v vs)) 

unvarianted :: (Unvariant' s a, Unvariant' t b, SameLabels s t, SameLength s t, Functor f) => (a -> f b) -> Variant s -> f (Variant t) Source

Lens (Variant s) (Variant t) a b

Analogue of Control.Lens.chosen :: Lens (Either a a) (Either b b) a b

unvarianted' :: (HAllEqVal ((:) * (Tagged * () b) s) b1, HAllEqVal s b1, HAllEqVal' ((:) * (Tagged * () b) s), Unvariant1 Bool b1 s b, SameLength' * * s s, SameLabels [*] [*] s s, Functor f) => (b -> f b) -> Variant s -> f (Variant s) Source

Lens' (Variant s) a

where we might have s ~ '[Tagged t1 a, Tagged t2 a]


class ZipVariant x y xy | x y -> xy, xy -> x y where Source

Applies to variants that have the same labels in the same order. A generalization of

zipEither :: Either a b -> Either a b -> Maybe (Either (a,a) (b,b))
zipEither (Left a) (Left a') = Just (Left (a,a'))
zipEither (Right a) (Right a') = Just (Right (a,a'))
zipEither _ _ = Nothing

see HZip for zipping other collections


zipVariant :: Variant x -> Variant y -> Maybe (Variant xy) Source


ZipVariant ([] *) ([] *) ([] *) 
((~) * tx (Tagged k t x), (~) * ty (Tagged k t y), (~) * txy (Tagged k t (x, y)), ZipVariant xs ys zs, MkVariant k t (x, y) ((:) * txy zs)) => ZipVariant ((:) * tx xs) ((:) * ty ys) ((:) * txy zs) 

with a record

class (SameLength v v', SameLabels v v') => ZipVR fs v v' | fs v -> v' where Source

Apply a record of functions to a variant of values. The functions are selected based on those having the same label as the value.


zipVR_ :: Record fs -> Variant v -> Variant v' Source

zipVR is probably a better choice in most situations, since it requires that fs has one function for every element of v


ZipVR fs ([] *) ([] *) 
((~) * lv (Tagged k l v), (~) * lv' (Tagged k l v'), HMemberM * (Label k l) (LabelsOf fs) b, HasFieldM k l (Record fs) f, (~) * (DemoteMaybe (v -> v) f) (v -> v'), MkVariant k l v' ((:) * lv' rs), ZipVR fs vs rs) => ZipVR fs ((:) * lv vs) ((:) * lv' rs) 

zipVR :: (SameLabels fs v, SameLength fs v, ZipVR fs v v', ZipVRCxt fs v v') => Record fs -> Variant v -> Variant v' Source

>>> let xy = x .*. y .*. emptyProxy
>>> let p = Proxy `asLabelsOf` xy
>>> let vs = [ mkVariant x 1.0 p, mkVariant y () p ]
>>> zipVR (hBuild (+1) id) `map` vs

type family ZipVRCxt fs xs ys :: Constraint Source

Lets zipVR act as if ZipVR fs v v' had an FD v v' -> fs

ZipVRCxt [Tagged s f,  Tagged t g]
         [Tagged s fx, Tagged t gx]
         [Tagged s fy, Tagged t gy]
  = (f ~ (fx -> fy), g ~ (gx -> gy))


type ZipVRCxt ([] *) ([] *) ([] *) = () 
type ZipVRCxt ((:) * (Tagged k s f) fs) ((:) * (Tagged k s x) xs) ((:) * (Tagged k s y) ys) = ((~) * f (x -> y), ZipVRCxt fs xs ys) 


Alternative Eq

eqVariant :: (HAllEqVal ((:) * (Tagged * () Bool) (HMapOutV_gety x Bool)) b, HAllEqVal (HMapOutV_gety x Bool) b, Unvariant1 Bool b (HMapOutV_gety x Bool) Bool, ZipVariant x1 y x, HMapAux Variant (HFmap UncurryEq) x (HMapOutV_gety x Bool), SameLength' * * (HMapOutV_gety x Bool) x, SameLength' * * x (HMapOutV_gety x Bool)) => Variant x1 -> Variant y -> Bool Source

implemented like and (zipWith (==) xs ys). Behaves the same as the Eq instances for Variant

data UncurryEq Source




((~) * ee (e, e), Eq e, (~) * bool Bool) => ApplyAB UncurryEq ee bool 







class ProjectVariant x y where Source

convert a variant with more fields into one with fewer (or the same) fields.

>>> let ty = Proxy :: Proxy [Tagged "left" Int, Tagged "right" Int]
>>> let l = mkVariant _left 1 ty
>>> let r = mkVariant _right 2 ty
>>> map projectVariant [l, r] :: [Maybe (Variant '[Tagged "left" Int])]
[Just V{left=1},Nothing]

rearrangeVariant = fromJust . projectVariant is one implementation of rearrangeVariant, since the result can have the same fields with a different order:

>>> let yt = Proxy :: Proxy [Tagged "right" Int, Tagged "left" Int]
>>> map projectVariant [l, r] `asTypeOf` [Just (mkVariant _left 0 yt)]
[Just V{left=1},Just V{right=2}]


ProjectVariant x ([] *) 
(ProjectVariant x ys, HasField k t (Variant x) (Maybe y), HOccursNot * (Label k t) (LabelsOf ys), (~) * ty (Tagged k t y)) => ProjectVariant x ((:) * ty ys) 

class HAllTaggedLV y => ProjectExtendVariant x y where Source

projectExtendVariant = fmap extendVariant . projectVariant

where intermediate variant is as large as possible. Used to implement Data.HList.Labelable.projected

Note that:

>>> let r = projectExtendVariant (mkVariant1 Label 1 :: Variant '[Tagged "x" Int])
>>> r :: Maybe (Variant '[Tagged "x" Integer])


HAllTaggedLV y => ProjectExtendVariant ([] *) y 
((~) * lv (Tagged k l v), HMemberM * lv y inY, ProjectExtendVariant' inY lv y, ProjectExtendVariant xs y) => ProjectExtendVariant ((:) * lv xs) y 

class ProjectExtendVariant' inY lv y where Source


projectExtendVariant' :: Proxy inY -> lv -> Maybe (Variant y) Source


ProjectExtendVariant' (Nothing [*]) lv y 
(MkVariant k l v y, (~) * lv (Tagged k l v)) => ProjectExtendVariant' (Just [*] t) lv y 

class (ProjectVariant x yin, ProjectVariant x yout) => SplitVariant x yin yout where Source


splitVariant :: Variant x -> Either (Variant yin) (Variant yout) Source


(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 

class (HAllTaggedLV y, HAllTaggedLV x) => ExtendsVariant x y where Source

projectVariant . extendsVariant = Just (when the types match up)

extendVariant is a special case


(HAllTaggedLV x, Unvariant ((:) * le ([] *)) e, MkVariant k l e x, (~) * le (Tagged k l e)) => ExtendsVariant ((:) * le ([] *)) x 
(MkVariant k l e y, (~) * le (Tagged k l e), ExtendsVariant ((:) * b bs) y) => ExtendsVariant ((:) * le ((:) * b bs)) y 

rearrangeVariant :: (SameLength v v', ExtendsVariant v v') => Variant v -> Variant v' Source

rearrangeVariant is a specialization of extendsVariant whose result is always . see also rearranged

hMaybied :: (VariantToHMaybied v1 x, VariantToHMaybied v r, HFoldr HMaybiedToVariantFs [Variant ([] *)] x [Variant v1], HMapAux HList (HFmap HCastF) x r, SameLength' * * x r, SameLength' * * r x, Choice p, Applicative f) => p (Variant v1) (f (Variant v)) -> p (Record x) (f (Record r)) Source

Prism (Record tma) (Record tmb) (Variant ta) (Variant tb)

see hMaybied'

data HCastF Source




((~) * mx (Maybe x), (~) * my (Maybe y), HCast y x) => ApplyAB HCastF mx my 

hMaybied' :: (VariantToHMaybied v x, HFoldr HMaybiedToVariantFs [Variant ([] *)] x [Variant v], HMapAux HList (HFmap HCastF) x x, SameLength' * * x x, Choice p, Applicative f) => p (Variant v) (f (Variant v)) -> p (Record x) (f (Record x)) Source

Prism' (Record tma) (Variant ta)

where tma and tmb are lists like

tma ~ '[Tagged x (Maybe a), Tagged y (Maybe b)]
ta  ~ '[Tagged x        a , Tagged y        b ]

If one element of the record is Just, the Variant will contain that element. Otherwise, the prism fails.


The types work out to define a prism:

l = prism' variantToHMaybied (listToMaybe . hMaybiedToVariants)

but the law: s^?l ≡ Just a ==> l # a ≡ s is not followed, because we could have:

  s, s2 :: Record '[Tagged "x" (Maybe Int), Tagged "y" (Maybe Char)]
  s = hBuild (Just 1) (Just '2')
  s2 = hBuild (Just 1) Nothing

  v :: Variant '[Tagged "x" Int, Tagged "y" Char]
  v = mkVariant (Label :: Label "x") 1 Proxy

So that s^?l == Just v. But l#v == s2 /= s, while the law requires l#v == s. hMaybied avoids this problem by only producing a value when there is only one present.

class VariantToHMaybied v r | v -> r, r -> v where Source


VariantToHMaybied ([] *) ([] *) 
(VariantToHMaybied v r, HReplicateF nr ConstTaggedNothing () r, (~) * tx (Tagged k t x), (~) * tmx (Tagged k t (Maybe x))) => VariantToHMaybied ((:) * tx v) ((:) * tmx r) 

data ConstTaggedNothing Source




(~) * y (Tagged k t (Maybe e)) => ApplyAB ConstTaggedNothing x y 

hMaybiedToVariants :: (HFoldr HMaybiedToVariantFs [Variant []] r [Variant v], VariantToHMaybied v r) => Record r -> [Variant v] Source

Every element of the record that is Just becomes one element in the resulting list. See hMaybied' example types that r and v can take.

data HMaybiedToVariantFs Source




((~) * x (Tagged k t (Maybe e), [Variant v]), (~) * y [Variant ((:) * (Tagged k t e) v)], MkVariant k t e ((:) * (Tagged k t e) v)) => ApplyAB HMaybiedToVariantFs x y