Safe Haskell | None |
---|---|
Language | Haskell2010 |
This module implements extensible variants using closed type families.
Synopsis
- data Label (s :: Symbol) = Label
- class KnownSymbol (n :: Symbol)
- type family AllUniqueLabels (r :: Row k) :: Constraint where ...
- type WellBehaved ρ = (Forall ρ Unconstrained1, AllUniqueLabels ρ)
- data Var (r :: Row *)
- data Row a
- type Empty = R '[]
- type (≈) a b = a ~ b
- class (r .! l) ≈ a => HasType l a r
- pattern IsJust :: forall l r. (AllUniqueLabels r, KnownSymbol l) => Label l -> (r .! l) -> Var r
- singleton :: KnownSymbol l => Label l -> a -> Var (l .== a)
- unSingleton :: forall l a. KnownSymbol l => Var (l .== a) -> (Label l, a)
- fromLabels :: forall c ρ f. (Alternative f, Forall ρ c, AllUniqueLabels ρ) => (forall l a. (KnownSymbol l, c a) => Label l -> f a) -> f (Var ρ)
- type family (r :: Row k) .\ (l :: Symbol) :: Constraint where ...
- class Lacks (l :: Symbol) (r :: Row *)
- type family (l :: Row k) .\/ (r :: Row k) where ...
- diversify :: forall r' r. Var r -> Var (r .\/ r')
- type family (l :: Row k) .+ (r :: Row k) :: Row k where ...
- update :: (KnownSymbol l, (r .! l) ≈ a) => Label l -> a -> Var r -> Var r
- focus :: forall l r r' a b p f. (AllUniqueLabels r, AllUniqueLabels r', KnownSymbol l, (r .! l) ≈ a, (r' .! l) ≈ b, r' ≈ ((r .- l) .\/ (l .== b)), Applicative f, Choice p) => Label l -> p a (f b) -> p (Var r) (f (Var r'))
- type family Modify (l :: Symbol) (a :: k) (r :: Row k) :: Row k where ...
- rename :: (KnownSymbol l, KnownSymbol l') => Label l -> Label l' -> Var r -> Var (Rename l l' r)
- type family Rename (l :: Symbol) (l' :: Symbol) (r :: Row k) :: Row k where ...
- impossible :: Var Empty -> a
- trial :: KnownSymbol l => Var r -> Label l -> Either (r .! l) (Var (r .- l))
- trial' :: KnownSymbol l => Var r -> Label l -> Maybe (r .! l)
- multiTrial :: forall x y. (AllUniqueLabels x, Forall (y .\\ x) Unconstrained1) => Var y -> Either (Var x) (Var (y .\\ x))
- view :: KnownSymbol l => Label l -> Var r -> Maybe (r .! l)
- restrict :: forall r r'. (WellBehaved r, Subset r r') => Var r' -> Maybe (Var r)
- split :: forall s r. (WellBehaved s, Subset s r) => Var r -> Either (Var s) (Var (r .\\ s))
- type family (r :: Row k) .! (t :: Symbol) :: k where ...
- type family (r :: Row k) .- (s :: Symbol) :: Row k where ...
- type family (l :: Row k) .\\ (r :: Row k) :: Row k where ...
- type (.==) (l :: Symbol) (a :: k) = Extend l a Empty
- toNative :: ToNative t => Var (NativeRow t) -> t
- fromNative :: FromNative t => t -> Var (NativeRow t)
- fromNativeGeneral :: FromNativeGeneral t ρ => t -> Var ρ
- type ToNative t = (Generic t, ToNativeG (Rep t))
- type FromNative t = (Generic t, FromNativeG (Rep t))
- type FromNativeGeneral t ρ = (Generic t, FromNativeGeneralG (Rep t) ρ)
- type family NativeRow t where ...
- type family Map (f :: a -> b) (r :: Row a) :: Row b where ...
- map :: forall c f r. Forall r c => (forall a. c a => a -> f a) -> Var r -> Var (Map f r)
- map' :: forall f r. Forall r Unconstrained1 => (forall a. a -> f a) -> Var r -> Var (Map f r)
- transform :: forall r c (f :: * -> *) (g :: * -> *). Forall r c => (forall a. c a => f a -> g a) -> Var (Map f r) -> Var (Map g r)
- transform' :: forall r (f :: * -> *) (g :: * -> *). Forall r Unconstrained1 => (forall a. f a -> g a) -> Var (Map f r) -> Var (Map g r)
- class Forall (r :: Row k) (c :: k -> Constraint)
- erase :: forall c ρ b. Forall ρ c => (forall a. c a => a -> b) -> Var ρ -> b
- eraseWithLabels :: forall c ρ s b. (Forall ρ c, IsString s) => (forall a. c a => a -> b) -> Var ρ -> (s, b)
- eraseZip :: forall c ρ b. Forall ρ c => (forall a. c a => a -> a -> b) -> Var ρ -> Var ρ -> Maybe b
- sequence :: forall f r. (Forall r Unconstrained1, Applicative f) => Var (Map f r) -> f (Var r)
- compose :: forall (f :: * -> *) (g :: * -> *) r. Forall r Unconstrained1 => Var (Map f (Map g r)) -> Var (Map (Compose f g) r)
- uncompose :: forall (f :: * -> *) (g :: * -> *) r. Forall r Unconstrained1 => Var (Map (Compose f g) r) -> Var (Map f (Map g r))
- labels :: forall ρ c s. (IsString s, Forall ρ c) => [s]
- coerceVar :: forall r1 r2. BiForall r1 r2 Coercible => Var r1 -> Var r2
- unsafeMakeVar :: forall r l. KnownSymbol l => Label l -> (r .! l) -> Var r
- unsafeInjectFront :: forall l a r. KnownSymbol l => Var (R r) -> Var (R ((l :-> a) ': r))
Types and constraints
data Label (s :: Symbol) Source #
A label
class KnownSymbol (n :: Symbol) #
This class gives the string associated with a type-level symbol. There are instances of the class for every concrete literal: "hello", etc.
Since: base-4.7.0.0
symbolSing
type family AllUniqueLabels (r :: Row k) :: Constraint where ... Source #
Are all of the labels in this Row unique?
AllUniqueLabels (R r) = AllUniqueLabelsR r |
type WellBehaved ρ = (Forall ρ Unconstrained1, AllUniqueLabels ρ) Source #
A convenient way to provide common, easy constraints
data Var (r :: Row *) Source #
The variant type.
Instances
(AllUniqueLabels r, KnownSymbol name, (r .! name) ≈ a, r ≈ ((r .- name) .\/ (name .== a))) => AsConstructor' name (Var r) a Source # | |
(AllUniqueLabels r, AllUniqueLabels r', KnownSymbol name, (r .! name) ≈ a, (r' .! name) ≈ b, r' ≈ ((r .- name) .\/ (name .== b))) => AsConstructor name (Var r) (Var r') a b Source # | Every possibility of a row-types based variant has an |
Forall r Eq => Eq (Var r) Source # | |
(Forall r Eq, Forall r Ord) => Ord (Var r) Source # | |
Forall r Show => Show (Var r) Source # | |
GenericVar r => Generic (Var r) Source # | |
Forall r NFData => NFData (Var r) Source # | |
Defined in Data.Row.Variants | |
type Rep (Var r) Source # | |
Defined in Data.Row.Variants |
The kind of rows. This type is only used as a datakind. A row is a typelevel entity telling us which symbols are associated with which types.
Construction
class (r .! l) ≈ a => HasType l a r Source #
Alias for (r .! l) ≈ a
. It is a class rather than an alias, so that
it can be partially applied.
pattern IsJust :: forall l r. (AllUniqueLabels r, KnownSymbol l) => Label l -> (r .! l) -> Var r Source #
A pattern for variants; can be used to both destruct a variant when in a pattern position or construct one in an expression position.
singleton :: KnownSymbol l => Label l -> a -> Var (l .== a) Source #
A quick constructor to create a singleton variant.
unSingleton :: forall l a. KnownSymbol l => Var (l .== a) -> (Label l, a) Source #
A quick destructor for singleton variants.
fromLabels :: forall c ρ f. (Alternative f, Forall ρ c, AllUniqueLabels ρ) => (forall l a. (KnownSymbol l, c a) => Label l -> f a) -> f (Var ρ) Source #
Initialize a variant from a producer function that accepts labels. If this function returns more than one possibility, then one is chosen arbitrarily to be the value in the variant.
Extension
type family (r :: Row k) .\ (l :: Symbol) :: Constraint where ... infixl 4 Source #
Does the row lack (i.e. it does not have) the specified label?
class Lacks (l :: Symbol) (r :: Row *) Source #
Alias for .\
. It is a class rather than an alias, so that
it can be partially applied.
Instances
r .\ l => Lacks l r Source # | |
Defined in Data.Row.Internal |
type family (l :: Row k) .\/ (r :: Row k) where ... infixl 6 Source #
The minimum join of the two rows.
diversify :: forall r' r. Var r -> Var (r .\/ r') Source #
Make the variant arbitrarily more diverse.
Modification
update :: (KnownSymbol l, (r .! l) ≈ a) => Label l -> a -> Var r -> Var r Source #
If the variant exists at the given label, update it to the given value. Otherwise, do nothing.
focus :: forall l r r' a b p f. (AllUniqueLabels r, AllUniqueLabels r', KnownSymbol l, (r .! l) ≈ a, (r' .! l) ≈ b, r' ≈ ((r .- l) .\/ (l .== b)), Applicative f, Choice p) => Label l -> p a (f b) -> p (Var r) (f (Var r')) Source #
If the variant exists at the given label, focus on the value associated with it. Otherwise, do nothing.
type family Modify (l :: Symbol) (a :: k) (r :: Row k) :: Row k where ... Source #
Type level Row modification
rename :: (KnownSymbol l, KnownSymbol l') => Label l -> Label l' -> Var r -> Var (Rename l l' r) Source #
Rename the given label.
type family Rename (l :: Symbol) (l' :: Symbol) (r :: Row k) :: Row k where ... Source #
Type level row renaming
Destruction
impossible :: Var Empty -> a Source #
A Variant with no options is uninhabited.
trial :: KnownSymbol l => Var r -> Label l -> Either (r .! l) (Var (r .- l)) Source #
Convert a variant into either the value at the given label or a variant without that label. This is the basic variant destructor.
trial' :: KnownSymbol l => Var r -> Label l -> Maybe (r .! l) Source #
A version of trial
that ignores the leftover variant.
multiTrial :: forall x y. (AllUniqueLabels x, Forall (y .\\ x) Unconstrained1) => Var y -> Either (Var x) (Var (y .\\ x)) Source #
A trial over multiple types
view :: KnownSymbol l => Label l -> Var r -> Maybe (r .! l) Source #
A convenient function for using view patterns when dispatching variants. For example:
myShow :: Var ("y" '::= String :| "x" '::= Int :| Empty) -> String myShow (view x -> Just n) = "Int of "++show n myShow (view y -> Just s) = "String of "++s
restrict :: forall r r'. (WellBehaved r, Subset r r') => Var r' -> Maybe (Var r) Source #
Arbitrary variant restriction. Turn a variant into a subset of itself.
split :: forall s r. (WellBehaved s, Subset s r) => Var r -> Either (Var s) (Var (r .\\ s)) Source #
Split a variant into two sub-variants.
Types for destruction
type family (r :: Row k) .- (s :: Symbol) :: Row k where ... infixl 6 Source #
Type level Row element removal
type family (l :: Row k) .\\ (r :: Row k) :: Row k where ... infixl 6 Source #
Type level Row difference. That is, l
is the row remaining after
removing any matching elements of .\\
rr
from l
.
type (.==) (l :: Symbol) (a :: k) = Extend l a Empty infix 7 Source #
A type level way to create a singleton Row.
Native Conversion
The toNative
and fromNative
functions allow one to convert between
Var
s and regular Haskell data types ("native" types) that have the same
number of constructors such that each constructor has one field and the same
name as one of the options of the Var
, which has the same type as that field.
As expected, they compose to form the identity. Alternatively, one may use
fromNativeGeneral
, which allows a variant with excess options to still be
transformed to a native type. Because of this, fromNativeGeneral
requires a type
application (although fromNative
does not). The only requirement is that
the native Haskell data type be an instance of Generic
.
For example, consider the following simple data type:
>>>
data Pet = Dog {age :: Int} | Cat {age :: Int} deriving (Generic, Show)
Then, we have the following:
>>>
toNative $ IsJust (Label @"Dog") 3 :: Pet
Dog {age = 3}>>>
V.fromNative $ Dog 3 :: Var ("Dog" .== Int .+ "Cat" .== Int)
{Dog=3}
toNative :: ToNative t => Var (NativeRow t) -> t Source #
Convert a variant to a native Haskell type.
fromNative :: FromNative t => t -> Var (NativeRow t) Source #
Convert a Haskell record to a row-types Var.
fromNativeGeneral :: FromNativeGeneral t ρ => t -> Var ρ Source #
Convert a Haskell record to a row-types Var.
type FromNative t = (Generic t, FromNativeG (Rep t)) Source #
type FromNativeGeneral t ρ = (Generic t, FromNativeGeneralG (Rep t) ρ) Source #
Row operations
Map
type family Map (f :: a -> b) (r :: Row a) :: Row b where ... Source #
Map a type level function over a Row.
map :: forall c f r. Forall r c => (forall a. c a => a -> f a) -> Var r -> Var (Map f r) Source #
A function to map over a variant given a constraint.
map' :: forall f r. Forall r Unconstrained1 => (forall a. a -> f a) -> Var r -> Var (Map f r) Source #
A function to map over a variant given no constraint.
transform :: forall r c (f :: * -> *) (g :: * -> *). Forall r c => (forall a. c a => f a -> g a) -> Var (Map f r) -> Var (Map g r) Source #
Lifts a natrual transformation over a variant. In other words, it acts as a
variant transformer to convert a variant of f a
values to a variant of g a
values. If no constraint is needed, instantiate the first type argument with
Unconstrained1
.
transform' :: forall r (f :: * -> *) (g :: * -> *). Forall r Unconstrained1 => (forall a. f a -> g a) -> Var (Map f r) -> Var (Map g r) Source #
A form of transformC
that doesn't have a constraint on a
Fold
class Forall (r :: Row k) (c :: k -> Constraint) Source #
Any structure over a row in which every element is similarly constrained can be metamorphized into another structure over the same row.
Instances
(KnownSymbol ℓ, c τ, Forall (R ρ) c) => Forall (R ((ℓ :-> τ) ': ρ) :: Row k) (c :: k -> Constraint) Source # | |
Defined in Data.Row.Internal metamorph :: Proxy h -> (f Empty -> g Empty) -> (forall (ℓ0 :: Symbol) (τ0 :: k0) (ρ0 :: [LT k0]). (KnownSymbol ℓ0, c τ0) => Label ℓ0 -> f (R ((ℓ0 :-> τ0) ': ρ0)) -> (h τ0, f (R ρ0))) -> (forall (ℓ1 :: Symbol) (τ1 :: k0) (ρ1 :: [LT k0]). (KnownSymbol ℓ1, c τ1) => Label ℓ1 -> h τ1 -> g (R ρ1) -> g (R ((ℓ1 :-> τ1) ': ρ1))) -> f (R ((ℓ :-> τ) ': ρ)) -> g (R ((ℓ :-> τ) ': ρ)) Source # metamorph' :: Proxy h -> (f Empty -> g Empty) -> (forall (ℓ0 :: Symbol) (τ0 :: k0) (ρ0 :: [LT k0]). (KnownSymbol ℓ0, c τ0) => Label ℓ0 -> f (R ((ℓ0 :-> τ0) ': ρ0)) -> Either (h τ0) (f (R ρ0))) -> (forall (ℓ1 :: Symbol) (τ1 :: k0) (ρ1 :: [LT k0]). (KnownSymbol ℓ1, c τ1) => Label ℓ1 -> Either (h τ1) (g (R ρ1)) -> g (R ((ℓ1 :-> τ1) ': ρ1))) -> f (R ((ℓ :-> τ) ': ρ)) -> g (R ((ℓ :-> τ) ': ρ)) Source # | |
Forall (R ([] :: [LT k]) :: Row k) (c :: k -> Constraint) Source # | |
Defined in Data.Row.Internal metamorph :: Proxy h -> (f Empty -> g Empty) -> (forall (ℓ :: Symbol) (τ :: k0) (ρ :: [LT k0]). (KnownSymbol ℓ, c τ) => Label ℓ -> f (R ((ℓ :-> τ) ': ρ)) -> (h τ, f (R ρ))) -> (forall (ℓ :: Symbol) (τ :: k0) (ρ :: [LT k0]). (KnownSymbol ℓ, c τ) => Label ℓ -> h τ -> g (R ρ) -> g (R ((ℓ :-> τ) ': ρ))) -> f (R []) -> g (R []) Source # metamorph' :: Proxy h -> (f Empty -> g Empty) -> (forall (ℓ :: Symbol) (τ :: k0) (ρ :: [LT k0]). (KnownSymbol ℓ, c τ) => Label ℓ -> f (R ((ℓ :-> τ) ': ρ)) -> Either (h τ) (f (R ρ))) -> (forall (ℓ :: Symbol) (τ :: k0) (ρ :: [LT k0]). (KnownSymbol ℓ, c τ) => Label ℓ -> Either (h τ) (g (R ρ)) -> g (R ((ℓ :-> τ) ': ρ))) -> f (R []) -> g (R []) Source # |
erase :: forall c ρ b. Forall ρ c => (forall a. c a => a -> b) -> Var ρ -> b Source #
A standard fold
eraseWithLabels :: forall c ρ s b. (Forall ρ c, IsString s) => (forall a. c a => a -> b) -> Var ρ -> (s, b) Source #
A fold with labels
eraseZip :: forall c ρ b. Forall ρ c => (forall a. c a => a -> a -> b) -> Var ρ -> Var ρ -> Maybe b Source #
A fold over two row type structures at once
Sequence
sequence :: forall f r. (Forall r Unconstrained1, Applicative f) => Var (Map f r) -> f (Var r) Source #
Applicative sequencing over a variant
Compose
We can easily convert between mapping two functors over the types of a row and mapping the composition of the two functors. The following two functions perform this composition with the gaurantee that:
>>>
compose . uncompose = id
>>>
uncompose . compose = id
compose :: forall (f :: * -> *) (g :: * -> *) r. Forall r Unconstrained1 => Var (Map f (Map g r)) -> Var (Map (Compose f g) r) Source #
Convert from a variant where two functors have been mapped over the types to one where the composition of the two functors is mapped over the types.
uncompose :: forall (f :: * -> *) (g :: * -> *) r. Forall r Unconstrained1 => Var (Map (Compose f g) r) -> Var (Map f (Map g r)) Source #
Convert from a variant where the composition of two functors have been mapped over the types to one where the two functors are mapped individually one at a time over the types.
labels
labels :: forall ρ c s. (IsString s, Forall ρ c) => [s] Source #
Return a list of the labels in a row type.
Coerce
coerceVar :: forall r1 r2. BiForall r1 r2 Coercible => Var r1 -> Var r2 Source #
Coerce a variant to a coercible representation. The BiForall
in the context
indicates that the type of any option in r1
can be coerced to the type of
the corresponding option in r2
.
Internally, this is implemented just with unsafeCoerce
, but we provide the
following implementation as a proof:
newtype ConstR a b = ConstR { unConstR :: Var a } newtype FlipConstR a b = FlipConstR { unFlipConstR :: Var b } coerceVar = unFlipConstR . biMetamorph' @_ @_ @r1 @r2 @Coercible @ConstR @FlipConstR @Const Proxy doNil doUncons doCons . ConstR where doNil = impossible . unConstR doUncons l = (Const +++ ConstR) . flip trial l . unConstR doCons :: forall ℓ τ1 τ2 ρ1 ρ2. (KnownSymbol ℓ, Coercible τ1 τ2) => Label ℓ -> Either (Const τ1 τ2) (FlipConstR ('R ρ1) ('R ρ2)) -> FlipConstR ('R (ℓ :-> τ1 ': ρ1)) ('R (ℓ :-> τ2 ': ρ2)) doCons l (Left (Const x)) = FlipConstR $ unsafeMakeVar l (coerce @τ1 @τ2 x) doCons _ (Right (FlipConstR v)) = FlipConstR $ unsafeInjectFront v
UNSAFE operations
unsafeMakeVar :: forall r l. KnownSymbol l => Label l -> (r .! l) -> Var r Source #
An unsafe way to make a Variant. This function does not guarantee that the labels are all unique.
unsafeInjectFront :: forall l a r. KnownSymbol l => Var (R r) -> Var (R ((l :-> a) ': r)) Source #
A helper function for unsafely adding an element to the front of a variant.
This can cause the type of the resulting variant to be malformed, for instance,
if the variant already contains labels that are lexicographically before the
given label. Realistically, this function should only be used when writing
calls to metamorph
.