variant-1.0.2: Variant and EADT
Safe HaskellNone
LanguageHaskell2010

Data.Variant

Description

Open sum type

V (for Variant) is a sum type, i.e. a wrapper for a value which can be of different types. For instance in the following code x is a variant whose value can be an Int, a Float or a String:

import Data.Variant

x :: V [Int,Float,String]

We use a type-level list of types to statically constrain the possible value types. Compared to usual sum types (e.g. Either Int Float) it allows us to have variants which can contain any number of types and to manipulate (extend/filter/etc.) the list in a type-safe way and without requiring new data types.

See also

  • Data.Variant.VEither is a variant biased towards the first type in the list, just like Either a b is biased towards the second type (b), allowing instances such as instance Functor (VEither a) which we do not have for V.
  • Data.Variant.Excepts is a multi-exception monad transformer wrapping VEither.
  • Data.Variant.EADT supports recursive sum types based on Variant (Extensible ADTs).

Why Variant?

In the functional programming world we use algebraic data types (ADT), more specifically sum types, to indicate that a value can be of two or more different types:

x,y :: Either String Int
x = Left "yo"
y = Right 10

What if we want to support more than two types?

Solution 1: sum types

We could use different sum types with different constructors for each arity (number of different types that the value can have).

data SumOf3 a b c   = S3_0 a | S3_1 b | S3_2 c
data SumOf4 a b c d = S4_0 a | S4_1 b | S4_2 c | S4_3 d

But it is quite hard to work with that many different types and constructors as we cannot easily define generic functions working on different sum types without a combinatorial explosion.

Solution 2: recursive ADT

Instead of adding new sum types we can use a nest of Either:

type SumOf3 a b c   = Either a (Either b c)
type SumOf4 a b c d = Either a (Either b (Either c d))

Or more generically:

data Union (as :: [Type]) where
  Union :: Either (Union as) a -> Union (a : as)

This time we can define generic functions without risking a combinatorial explosion. The drawback however is that we have changed the representation: instead of tag + value where tag is in the range [0,arity-1] we have a nest of tag + (tag + (... (tag + value))) where tag is in the range [0,1]. It is both inefficient in space and in time (accessing the tag value is in O(arity)).

Solution 3: variant

V gets the best of both approaches: it has the generic interface of the "recursive ADT" solution and the efficient representation of the "sum types" solution.

data Variant (types :: [Type]) = Variant {-# UNPACK #-} !Word Any

type role Variant representational

The efficient representation is ensured by the definition of the V datatype: an unpacked Word for the tag and a "pointer" to the value.

The phantom type list types contains the list of possible types for the value. The tag value is used as an index into this list to know the effective type of the value.

Creating Variant values

The easiest way to create a variant value is to use the V pattern synonym:

x,y :: V [String,Int]
x = V "test"
y = V @Int 10

Note: for now the compiler cannot use the variant value type list to infer the type of the variant value! In the previous example we have to specify the Int type. Even if it is clear (for us) that it is the obvious unique possibility, it is ambiguous for the compiler.

We can also explicitly create a variant by specifying the index (starting from 0) of the value type with toVariantAt:

x :: V [Int,String,Float]
x = toVariantAt @2 5.0

It is especially useful if for some reason we want to have the same type more than once in the variant value type list:

y :: V [Int,Int,String,Int,Float]
y = toVariantAt @1 5

Pattern matching

Direct pattern matching with V

Matching a variant value can be done with the V pattern synonym too:

f :: V [String,Int] -> String
f = \case
   V s            -> "Found string: " ++ s
   V (i :: Int)   -> "Found int: " ++ show i
   _              -> undefined

Note: for now the compiler cannot use the variant value type list to infer that the pattern-match is complete. Hence we need the wildcard match to avoid a warning.

See Data.Variant.ContFlow for safe alternatives that do not require a wildcard match and that provide better type inference.

Basic errors

If you try to set or match a value type that is not valid, you get a compile-time error:

x :: V [String,Int]
x = V @Float 10

-- error: `Float' is not a member of [String, Int]

Safe pattern matching with continuations

See Data.Variant.ContFlow for safe pattern matching using multi-continuations (>:> and >%:>) that ensure completeness at compile time.

Operations by index

We can retrieve values by index with fromVariantAt:

x :: V [Int,String,Float]
x = toVariantAt @2 5.0

> fromVariantAt @0 x
Nothing
> fromVariantAt @1 x
Nothing
> fromVariantAt @2 x
Just 5.0

Generic variant functions (variant-polymorphic functions)

Splitting variants

We can chose to handle only a subset of the possible value types of a Variant by using splitVariant. This is very useful when your variant is open (e.g. an exception type) and you want to perform an action for some particular types while ignoring the others (e.g. passing the unhandled exceptions to the caller).

For instance in the following example we only handle Int and Float values. The other ones are considered as left-overs:

printNum v = case splitVariant @[Float,Int] v of
   Right v -> v >%:>
      ( \f -> putStrLn ("Found float: " ++ show (f :: Float))
      , \i -> putStrLn ("Found int: " ++ show (i :: Int))
      )
   Left leftovers -> putStrLn "Not a supported number!"

Note that the printNum function above is generic and can be applied to any Variant type.

Membership constraints: (:<), (:<<), (:<?) #membership

The c :< cs constraint statically ensures that the type c is in the cs type list and that we can set and match it in a variant with type V cs. For example:

newtype Error = Error String

showError :: (Error :< cs) => V cs -> String
showError = \case
   V (Error s) -> "Found error: " ++ s
   _           -> "Not an Error!"

Note that to shorten a list of constraints such as (A :< xs, B :< xs, C :< xs) you can use the (:<<) operator: [A,B,C] :<< xs.

The c :< cs constraint statically ensures that the type c is in the cs type list. However in some cases we want to write generic functions that work on variants even if they cannot contain the given type.

The (:<?) constraint and the VMaybe pattern can be used for this:

showErrorMaybe :: (Error :<? cs) => V cs -> String
showErrorMaybe = \case
   VMaybe (Error s) -> "Found error: " ++ s
   _                -> "Not an Error!"

Shrinking variants with popVariant

A very common use of variants is to pattern match on a specific value type they can contain and to get a new variant containing the left-over value types. This is done with popVariant or popVariantMaybe and the Remove type family. For example:

filterError :: Error :<? cs => V cs -> V (Remove Error cs)
filterError v = case popVariantMaybe v of
   Right (Error s) -> error ("Found error: " ++ s)
   Left  v'        -> v' -- left-over variant!

Notice how an Error value cannot be present anymore in the variant type returned by filterError and how this function is generic as it supports any variant as an input.

Conversions

Singleton conversion

We can easily convert between a variant with a single value type and this value type with variantToValue and variantFromValue:

intV :: V [Int]
intV = V @Int 10

> variantToValue intV
10

> :t variantFromValue "Test"
variantFromValue "Test" :: V [String]

Either conversion

variantFromEither and variantToEither can be used to convert between a variant of arity 2 and the Either data type:

eith :: Either Int String
eith = Left 10

> :t variantFromEither eith
variantFromEither eith :: V [String, Int]

x,y :: V [String,Int]
x = V "test"
y = V @Int 10

> variantToEither x
Right "test"

> variantToEither y
Left 10

Extending the list of supported types

We can extend the value types of a variant by appending or prepending a list of types with appendVariant and prependVariant:

x :: V [String,Int]
x = V "test"

data A = A
data B = B

px = prependVariant @[A,B] x
ax = appendVariant @[A,B] x

> :t ax
ax :: V [String, Int, A, B]

> :t px
px :: V [A, B, String, Int]

Appending and prepending are very cheap operations: appending just messes with types and performs nothing at runtime; prepending only increases the tag value at runtime by a constant number.

Variant lifting (extending and reordering)

We can extend and reorder the value types of a variant with liftVariant:

x :: V [String,Int]
x = V "test"

-- adding Double and Float, and reordering
y :: V [Double,Int,Float,String]
y = liftVariant x

You can use the LiftVariant constraint to write generic code and to ensure that the type list is is a subset of os:

liftX :: (LiftVariant is (Double : Float : is))
      => V is -> V (Double : Float : is)
liftX = liftVariant

> :t liftX x
liftX x :: V [Double, Float, String, Int]

Removing duplicates (nub)

If the list of types of a variant contains the same type more than once, we can decide to only keep one of them with nubVariant:

> z = nubVariant (V "test" :: V [String,Int,Double,Float,Double,String])
> :t z
z :: V [String, Int, Double, Float]

Flattening nested variants

If the value types of a variant are themselves variants, you can flatten them with flattenVariant:

x :: V [String,Int]
x = V "test"

nest :: V [ V [String,Int], V [Float,Double]]
nest = V x

> :t flattenVariant nest
flattenVariant nest :: V [String, Int, Float, Double]

Joining variants of functors/monads

We can transform a variant of functor values (e.g., V [m a, m b, m c]) into a single functor value (e.g., m (V [a,b,c])) with joinVariant:

fs0,fs1,fs2 :: V [ Maybe Int, Maybe String, Maybe Double]
fs0 = V @(Maybe Int) (Just 10)
fs1 = V (Just "Test")
fs2 = V @(Maybe Double) Nothing

> joinVariant @Maybe fs0
Just (V @Int 10)

> joinVariant @Maybe fs1
Just (V @[Char] "Test")

> joinVariant @Maybe fs2
Nothing

It also works with IO for example:

ms0,ms1 :: V [ IO Int, IO String, IO Double]
ms0 = V @(IO Int) (printRet 10)
ms1 = V (printRet "Test")

> joinVariant @IO ms0
10
V @Int 10

> :t joinVariant @IO ms0
joinVariant @IO ms0 :: IO (V [Int, String, Double])

Writing generic code requires the use of the JoinVariant constraint and the resulting list of value types can be obtained with the ExtractM type family.

With IO it is possible to use joinVariantUnsafe which does not require the type application and does not use the JoinVariant type-class. However some other functor types are not supported (e.g., Maybe) and using joinVariantUnsafe with them makes the program crash at runtime.

Combining two variants (product)

We can combine two variants into a single variant containing a tuple with productVariant:

fl :: V [Float,Double]
fl = V @Float 5.0

d :: V [Int,Word]
d = V @Word 10

dfl = productVariant d fl

> dfl
V @(Word,Float) (10,5.0)

> :t dfl
dfl :: V [(Int, Float), (Int, Double), (Word, Float), (Word, Double)]

Converting variants to tuples/HList

We can convert a Variant into a tuple of Maybes with variantToTuple:

w :: V [String,Int,Double,Maybe Int]
w = V @Double 1.0

> variantToTuple w
(Nothing,Nothing,Just 1.0,Nothing)

And similarly into an HList (heterogeneous list) with variantToHList:

> variantToHList w
H[Nothing,Nothing,Just 1.0,Nothing]

Mapping

By type

We can easily apply a function f :: A -> B to a variant so that its value type A is replaced with B. If the value in the variant has type A, then f is applied to it to get the new value. Example:

x,y :: V [String,Int]
x = V "test"
y = V @Int 10

> mapVariant ((+5) :: Int -> Int) x
V @String "test"

> mapVariant ((+5) :: Int -> Int) y
V @Int 15

Note that the resulting variant may contain the same type more than once. To avoid this, we can either use nubVariant or directly use mapNubVariant:

> :t mapVariant (length :: String -> Int) x
mapVariant (length :: String -> Int) x :: V [Int, Int]

> :t mapNubVariant (length :: String -> Int) x
mapNubVariant (length :: String -> Int) x :: V [Int]

> mapNubVariant (length :: String -> Int) x
V @Int 4

By index

If we know the index of the value type we want to map, we can use mapVariantAt. Example:

x,y :: V [String,Int]
x = V "test"
y = V @Int 10

> mapVariantAt @0 length x
V @Int 4

> mapVariantAt @0 length y
V @Int 10

> mapVariantAt @1 (+5) x
V @[Char] "test"

> mapVariantAt @1 (+5) y
V @Int 15

Note that the compiler uses the type of the element whose index is given as first argument to infer the type of the functions, hence we do not need type ascriptions.

We can use mapVariantAtM to perform an applicative (or monadic) update.

First matching type

A variant can have the same type more than once in its value type list. mapVariant updates all the matching types in the list but sometimes that is not what we want. We can use mapVariantAt if we know the index of the type we want to update. We can also use mapVariantFirst to update only the first matching type:

vv :: V [Int,Int,Int]
vv = toVariantAt @1 5

> r0 = mapVariant (show :: Int -> String) vv
> r1 = mapVariantFirst (show :: Int -> String) vv

> :t r0
r0 :: V [String,String,String]

> :t r1
r1 :: V [String, Int, Int]

> r0
V @[Char] "5"

> r1
V @Int 5

We can also apply an applicative (or monadic) function with mapVariantFirstM.

Synopsis

Documentation

data V (l :: [Type]) Source #

A variant contains a value whose type is at the given position in the type list

Constructors

Variant !Word (Any :: Type) 

Instances

Instances details
(Exception x, Typeable xs, Exception (V xs)) => Exception (V (x ': xs)) Source # 
Instance details

Defined in Data.Variant

Methods

toException :: V (x ': xs) -> SomeException #

fromException :: SomeException -> Maybe (V (x ': xs)) #

displayException :: V (x ': xs) -> String #

Exception (V ('[] :: [Type])) Source # 
Instance details

Defined in Data.Variant

Methods

toException :: V ('[] :: [Type]) -> SomeException #

fromException :: SomeException -> Maybe (V ('[] :: [Type])) #

displayException :: V ('[] :: [Type]) -> String #

(Show x, Show (V xs)) => Show (V (x ': xs)) Source #

Show instance

>>> show (V @Int 10  :: V [Int,String,Double])
"10"
Instance details

Defined in Data.Variant

Methods

showsPrec :: Int -> V (x ': xs) -> ShowS #

show :: V (x ': xs) -> String #

showList :: [V (x ': xs)] -> ShowS #

Show (V ('[] :: [Type])) Source # 
Instance details

Defined in Data.Variant

Methods

showsPrec :: Int -> V ('[] :: [Type]) -> ShowS #

show :: V ('[] :: [Type]) -> String #

showList :: [V ('[] :: [Type])] -> ShowS #

(NFData x, NFData (V xs)) => NFData (V (x ': xs)) Source # 
Instance details

Defined in Data.Variant

Methods

rnf :: V (x ': xs) -> () #

NFData (V ('[] :: [Type])) Source # 
Instance details

Defined in Data.Variant

Methods

rnf :: V ('[] :: [Type]) -> () #

(Eq (V xs), Eq x) => Eq (V (x ': xs)) Source # 
Instance details

Defined in Data.Variant

Methods

(==) :: V (x ': xs) -> V (x ': xs) -> Bool #

(/=) :: V (x ': xs) -> V (x ': xs) -> Bool #

Eq (V ('[] :: [Type])) Source # 
Instance details

Defined in Data.Variant

Methods

(==) :: V ('[] :: [Type]) -> V ('[] :: [Type]) -> Bool #

(/=) :: V ('[] :: [Type]) -> V ('[] :: [Type]) -> Bool #

(Ord (V xs), Ord x) => Ord (V (x ': xs)) Source # 
Instance details

Defined in Data.Variant

Methods

compare :: V (x ': xs) -> V (x ': xs) -> Ordering #

(<) :: V (x ': xs) -> V (x ': xs) -> Bool #

(<=) :: V (x ': xs) -> V (x ': xs) -> Bool #

(>) :: V (x ': xs) -> V (x ': xs) -> Bool #

(>=) :: V (x ': xs) -> V (x ': xs) -> Bool #

max :: V (x ': xs) -> V (x ': xs) -> V (x ': xs) #

min :: V (x ': xs) -> V (x ': xs) -> V (x ': xs) #

Ord (V ('[] :: [Type])) Source # 
Instance details

Defined in Data.Variant

Methods

compare :: V ('[] :: [Type]) -> V ('[] :: [Type]) -> Ordering #

(<) :: V ('[] :: [Type]) -> V ('[] :: [Type]) -> Bool #

(<=) :: V ('[] :: [Type]) -> V ('[] :: [Type]) -> Bool #

(>) :: V ('[] :: [Type]) -> V ('[] :: [Type]) -> Bool #

(>=) :: V ('[] :: [Type]) -> V ('[] :: [Type]) -> Bool #

max :: V ('[] :: [Type]) -> V ('[] :: [Type]) -> V ('[] :: [Type]) #

min :: V ('[] :: [Type]) -> V ('[] :: [Type]) -> V ('[] :: [Type]) #

ContVariant xs => MultiCont (V xs) Source # 
Instance details

Defined in Data.Variant

Associated Types

type MultiContTypes (V xs) 
Instance details

Defined in Data.Variant

type MultiContTypes (V xs) = xs

Methods

toCont :: V xs -> ContFlow (MultiContTypes (V xs)) r Source #

toContM :: Monad m => m (V xs) -> ContFlow (MultiContTypes (V xs)) (m r) Source #

Flattenable (V ('[] :: [Type])) rs Source # 
Instance details

Defined in Data.Variant

Methods

toFlattenVariant :: Word -> V ('[] :: [Type]) -> rs

(Flattenable (V ys) (V rs), KnownNat (Length xs)) => Flattenable (V (V xs ': ys)) (V rs) Source # 
Instance details

Defined in Data.Variant

Methods

toFlattenVariant :: Word -> V (V xs ': ys) -> V rs

type MultiContTypes (V xs) Source # 
Instance details

Defined in Data.Variant

type MultiContTypes (V xs) = xs

variantIndex :: forall (a :: [Type]). V a -> Word Source #

Get Variant index

>>> let x = V "Test" :: V [Int,String,Double]
>>> variantIndex x
1
>>> let y = toVariantAt @0 10 :: V [Int,String,Double]
>>> variantIndex y
0

variantSize :: forall (xs :: [Type]). KnownNat (Length xs) => V xs -> Word Source #

Get variant size

>>> let x = V "Test" :: V [Int,String,Double]
>>> variantSize x
3
>>> let y = toVariantAt @0 10 :: V [Int,String,Double,Int]
>>> variantSize y
4

Patterns

pattern V :: c :< cs => c -> V cs Source #

Pattern synonym for Variant

Usage: case v of V (x :: Int) -> ... V (x :: String) -> ...

pattern VMaybe :: c :<? cs => c -> V cs Source #

Statically unchecked matching on a Variant

type (:<) x (xs :: [Type]) = (Member x xs, x :<? xs) Source #

A value of type "x" can be extracted from (V xs)

type family (xs :: [Type]) :<< (ys :: [Type]) where ... Source #

Forall x in xs, `x :< ys`

Equations

('[] :: [Type]) :<< ys = () 
(x ': xs) :<< ys = (x :< ys, xs :<< ys) 

type (:<?) x (xs :: [Type]) = (PopVariant x xs, ToVariantMaybe x xs) Source #

A value of type "x" **might** be extracted from (V xs). We don't check that "x" is in "xs".

Operations by index

toVariantAt :: forall (n :: Nat) (l :: [Type]). KnownNat n => Index n l -> V l Source #

Set the value with the given indexed type

>>> toVariantAt @1 10 :: V [Word,Int,Double]
10

toVariantHead :: forall x (xs :: [Type]). x -> V (x ': xs) Source #

Set the first value

>>> toVariantHead 10 :: V [Int,Float,Word]
10

toVariantTail :: forall x (xs :: [Type]). V xs -> V (x ': xs) Source #

Set the tail

>>> let x = V @Int 10 :: V [Int,String,Float]
>>> let y = toVariantTail @Double x
>>> :t y
y :: V [Double, Int, String, Float]

fromVariantAt :: forall (n :: Nat) (l :: [Type]). KnownNat n => V l -> Maybe (Index n l) Source #

Try to get a value by index into the type list

>>> let x = V "Test" :: V [Int,String,Float]
>>> fromVariantAt @0 x
Nothing
>>> fromVariantAt @1 x
Just "Test"
>>> fromVariantAt @2 x
Nothing

fromVariantHead :: forall x (xs :: [Type]). V (x ': xs) -> Maybe x Source #

Try to get the first variant value

>>> let x = V "Test" :: V [Int,String,Float]
>>> fromVariantHead x
Nothing
>>> let y = V @Int 10 :: V [Int,String,Float]
>>> fromVariantHead y
Just 10

popVariantAt :: forall (n :: Nat) (l :: [Type]). KnownNat n => V l -> Either (V (RemoveAt n l)) (Index n l) Source #

Pop a variant value by index, return either the value or the remaining variant

>>> let x = V @Word 10 :: V [Int,Word,Float]
>>> popVariantAt @0 x
Left 10
>>> popVariantAt @1 x
Right 10
>>> popVariantAt @2 x
Left 10

popVariantHead :: forall x (xs :: [Type]). V (x ': xs) -> Either (V xs) x Source #

Pop the head of a variant value

>>> let x = V @Word 10 :: V [Int,Word,Float]
>>> popVariantHead x
Left 10
>>> let y = V @Int 10 :: V [Int,Word,Float]
>>> popVariantHead y
Right 10

mapVariantAt :: forall (n :: Nat) a b (l :: [Type]). (KnownNat n, a ~ Index n l) => (a -> b) -> V l -> V (ReplaceN n b l) Source #

Update a single variant value by index

>>> import Data.Char (toUpper)
>>> let x = V @String "Test" :: V [Int,String,Float]
>>> mapVariantAt @1 (fmap toUpper) x
"TEST"
>>> mapVariantAt @0 (+1) x
"Test"

mapVariantAtM :: forall (n :: Nat) a b (l :: [Type]) m. (KnownNat n, Applicative m, a ~ Index n l) => (a -> m b) -> V l -> m (V (ReplaceN n b l)) Source #

Applicative update of a single variant value by index

Example with Maybe:

>>> let f s = if s == "Test" then Just (42 :: Word) else Nothing
>>> let x = V @String "Test" :: V [Int,String,Float]
>>> mapVariantAtM @1 f x
Just 42
>>> let y = V @String "NotTest" :: V [Int,String,Float]
>>> mapVariantAtM @1 f y
Nothing

Example with IO:

>>> v <- mapVariantAtM @0 print x
>>> :t v
v :: V [(), String, Float]
>>> v <- mapVariantAtM @1 print x
"Test"
>>> :t v
v :: V [Int, (), Float]
>>> v <- mapVariantAtM @2 print x
>>> :t v
v :: V [Int, [Char], ()]

foldMapVariantAt :: forall (n :: Nat) (l :: [Type]) (l2 :: [Type]). (KnownNat n, KnownNat (Length l2)) => (Index n l -> V l2) -> V l -> V (ReplaceAt n l l2) Source #

Update a variant value with a variant and fold the result

>>> newtype Odd  = Odd Int  deriving (Show)
>>> newtype Even = Even Int deriving (Show)
>>> let f x = if even x then V (Even x) else V (Odd x) :: V [Odd, Even]
>>> foldMapVariantAt @1 f (V @Int 10 :: V [Float,Int,Double])
Even 10
>>> foldMapVariantAt @1 f (V @Float 0.5 :: V [Float,Int,Double])
0.5

foldMapVariantAtM :: forall (n :: Nat) m (l :: [Type]) (l2 :: [Type]). (KnownNat n, KnownNat (Length l2), Monad m) => (Index n l -> m (V l2)) -> V l -> m (V (ReplaceAt n l l2)) Source #

Update a variant value with a variant and fold the result

bindVariant :: forall x (xs :: [Type]) (ys :: [Type]). KnownNat (Length ys) => V (x ': xs) -> (x -> V ys) -> V (Concat ys xs) Source #

Bind (>>=) for a Variant

constBindVariant :: forall (xs :: [Type]) (ys :: [Type]). V xs -> V ys -> V (Concat ys xs) Source #

Const bind (>>) for a Variant

variantHeadTail :: forall x u (xs :: [Type]). (x -> u) -> (V xs -> u) -> V (x ': xs) -> u Source #

List-like catamorphism

>>> let f = variantHeadTail (\i -> "Found Int: " ++ show i) (const "Something else")
>>> f (V @String "Test" :: V [Int,String,Float])
"Something else"
>>> f (V @Int 10 :: V [Int,String,Float])
"Found Int: 10"

mapVariantHeadTail :: forall x y (xs :: [Type]) (ys :: [Type]). (x -> y) -> (V xs -> V ys) -> V (x ': xs) -> V (y ': ys) Source #

Bimap Variant head and tail

>>> let f = mapVariantHeadTail (+5) (appendVariant @[Double,Char])
>>> f (V @Int 10 :: V [Int,Word,Float])
15
>>> f (V @Word 20 :: V [Int,Word,Float])
20

Operations by type

toVariant :: forall a (l :: [Type]). a :< l => a -> V l Source #

Put a value into a Variant

Use the first matching type index.

popVariant :: forall a (xs :: [Type]). a :< xs => V xs -> Either (V (Remove a xs)) a Source #

Extract a type from a variant. Return either the value of this type or the remaining variant

popVariantMaybe :: forall a (xs :: [Type]). a :<? xs => V xs -> Either (V (Remove a xs)) a Source #

Extract a type from a variant. Return either the value of this type or the remaining variant

fromVariant :: forall a (xs :: [Type]). a :< xs => V xs -> Maybe a Source #

Try to a get a value of a given type from a Variant

Equivalent to pattern V.

>>> let x = toVariantAt @2 10 :: V [Int,String,Int]
>>> fromVariant @Int x
Just 10
fromVariant @Double x

... error: Double not found in list: [Int, String, Int] ...

fromVariantMaybe :: forall a (xs :: [Type]). a :<? xs => V xs -> Maybe a Source #

Try to a get a value of a given type from a Variant that may not even support the given type.

>>> let x = V @Int 10 :: V [Int,String,Float]
>>> fromVariantMaybe @Int x
Just 10
>>> fromVariantMaybe @Double x
Nothing

fromVariantFirst :: forall a (l :: [Type]). Member a l => V l -> Maybe a Source #

Pick the first matching type of a Variant

>>> let x = toVariantAt @2 10 :: V [Int,String,Int]
>>> fromVariantFirst @Int x
Nothing

mapVariantFirst :: forall a b (n :: Nat) (l :: [Type]). (Member a l, n ~ IndexOf a l) => (a -> b) -> V l -> V (ReplaceN n b l) Source #

Update the first matching variant value

>>> let x = toVariantAt @0 10 :: V [Int,String,Int]
>>> mapVariantFirst @Int (+32) x
42
>>> let y = toVariantAt @2 10 :: V [Int,String,Int]
>>> mapVariantFirst @Int (+32) y
10

mapVariantFirstM :: forall a b (n :: Nat) (l :: [Type]) m. (Member a l, n ~ IndexOf a l, Applicative m) => (a -> m b) -> V l -> m (V (ReplaceN n b l)) Source #

Applicative update of the first matching variant value

Example with Maybe:

>>> let f s = if s == (42 :: Int) then Just "Yeah!" else Nothing
>>> mapVariantFirstM f (toVariantAt @0 42 :: V [Int,Float,Int])
Just "Yeah!"
>>> mapVariantFirstM f (toVariantAt @2 42 :: V [Int,Float,Int])
Just 42
>>> mapVariantFirstM f (toVariantAt @0 10 :: V [Int,Float,Int])
Nothing
>>> mapVariantFirstM f (toVariantAt @2 10 :: V [Int,Float,Int])
Just 10

Example with IO:

>>> mapVariantFirstM @Int print (toVariantAt @0 42 :: V [Int,Float,Int])
42
()
>>> mapVariantFirstM @Int print (toVariantAt @2 42 :: V [Int,Float,Int])
42

mapVariant :: forall a b (cs :: [Type]). MapVariant a b cs => (a -> b) -> V cs -> V (ReplaceAll a b cs) Source #

Map the matching types of a variant

>>> let add1 = mapVariant @Int (+1)
>>> add1 (toVariantAt @0 10 :: V [Int,Float,Int,Double])
11
>>> add1 (toVariantAt @2 10 :: V [Int,Float,Int, Double])
11

mapNubVariant :: forall a b (cs :: [Type]) (ds :: [Type]) (rs :: [Type]). (MapVariant a b cs, ds ~ ReplaceNS (IndexesOf a cs) b cs, rs ~ Nub ds, LiftVariant ds rs) => (a -> b) -> V cs -> V rs Source #

Map the matching types of a variant and nub the result

>>> let add1 = mapNubVariant @Int (+1)
>>> add1 (toVariantAt @0 10 :: V [Int,Float,Int,Double])
11
>>> add1 (toVariantAt @2 10 :: V [Int,Float,Int, Double])
11

foldMapVariantFirst :: forall a (n :: Nat) (l :: [Type]) (l2 :: [Type]). (KnownNat n, KnownNat (Length l2), n ~ IndexOf a l, a ~ Index n l) => (a -> V l2) -> V l -> V (ReplaceAt n l l2) Source #

Update a variant value with a variant and fold the result

foldMapVariantFirstM :: forall a (n :: Nat) (l :: [Type]) (l2 :: [Type]) m. (KnownNat n, KnownNat (Length l2), n ~ IndexOf a l, a ~ Index n l, Monad m) => (a -> m (V l2)) -> V l -> m (V (ReplaceAt n l l2)) Source #

Update a variant value with a variant and fold the result

foldMapVariant :: forall a (cs :: [Type]) (ds :: [Type]) (i :: Nat). (i ~ IndexOf a cs, a :< cs) => (a -> V ds) -> V cs -> V (InsertAt i (Remove a cs) ds) Source #

Update a variant value with a variant and fold the result

>>> newtype Odd  = Odd Int  deriving (Show)
>>> newtype Even = Even Int deriving (Show)
>>> let f x = if even x then V (Even x) else V (Odd x) :: V [Odd, Even]
>>> foldMapVariant @Int f (V @Int 10 :: V [Float,Int,Double])
Even 10
>>> foldMapVariant @Int f (V @Float 0.5 :: V [Float,Int,Double])
0.5

type family Member (x :: k) (xs :: [k]) where ... Source #

Constraint: x member of xs

Equations

Member (x :: k) (xs :: [k]) = MemberAtIndex (IndexOf x xs) x xs 

type family Remove (a :: k) (l :: [k]) :: [k] where ... Source #

Remove a in l

Equations

Remove (a :: k) ('[] :: [k]) = '[] :: [k] 
Remove (a :: k) (a ': as :: [k]) = Remove a as 
Remove (a :: k) (b ': as :: [k]) = b ': Remove a as 

type ReplaceAll a b (cs :: [Type]) = ReplaceNS (IndexesOf a cs) b cs Source #

type MapVariant a b (cs :: [Type]) = MapVariantIndexes a b cs (IndexesOf a cs) Source #

Generic operations with type classes

alterVariant :: forall c (a :: [Type]). AlterVariant c a => (forall x. c x => x -> x) -> V a -> V a Source #

Alter a variant. You need to specify the constraints required by the modifying function.

Usage: alterVariant NoConstraint id v alterVariant Resizable (resize 4) v

  • - Multiple constraints: class (Ord a, Num a) => OrdNum a instance (Ord a, Num a) => OrdNum a alterVariant @OrdNum foo v

traverseVariant :: forall c (a :: [Type]) m. (TraverseVariant c a m, Monad m) => (forall x. c x => x -> m x) -> V a -> m (V a) Source #

Traverse a variant. You need to specify the constraints required by the modifying function.

traverseVariant_ :: forall c (a :: [Type]) m. (TraverseVariant c a m, Monad m) => (forall x. c x => x -> m ()) -> V a -> m () Source #

Traverse a variant. You need to specify the constraints required by the modifying function.

reduceVariant :: forall c (a :: [Type]) r. ReduceVariant c a => (forall x. c x => x -> r) -> V a -> r Source #

Reduce a variant to a single value by using a class function. You need to specify the constraints required by the modifying function.

>>> let v = V "Yes" :: V [String,Bool,Char]
>>> reduceVariant @Show show v
"\"Yes\""
>>> let n = V (10 :: Int) :: V [Int,Word,Integer]
>>> reduceVariant @Integral fromIntegral n :: Int
10

class NoConstraint a Source #

Useful to specify a "Type -> Constraint" function returning an empty constraint

Instances

Instances details
NoConstraint a Source # 
Instance details

Defined in Data.Variant

class AlterVariant (c :: Type -> Constraint) (b :: [Type]) Source #

Minimal complete definition

alterVariant'

Instances

Instances details
AlterVariant c ('[] :: [Type]) Source # 
Instance details

Defined in Data.Variant

Methods

alterVariant' :: (forall a. c a => a -> a) -> Word -> (Any :: Type) -> Any :: Type

(AlterVariant c xs, c x) => AlterVariant c (x ': xs) Source # 
Instance details

Defined in Data.Variant

Methods

alterVariant' :: (forall a. c a => a -> a) -> Word -> (Any :: Type) -> Any :: Type

class TraverseVariant (c :: Type -> Constraint) (b :: [Type]) (m :: Type -> Type) Source #

Minimal complete definition

traverseVariant'

Instances

Instances details
TraverseVariant c ('[] :: [Type]) m Source # 
Instance details

Defined in Data.Variant

Methods

traverseVariant' :: (forall a. (Monad m, c a) => a -> m a) -> Word -> (Any :: Type) -> m (Any :: Type)

(TraverseVariant c xs m, c x, Monad m) => TraverseVariant c (x ': xs) m Source # 
Instance details

Defined in Data.Variant

Methods

traverseVariant' :: (forall a. (Monad m, c a) => a -> m a) -> Word -> (Any :: Type) -> m (Any :: Type)

class ReduceVariant (c :: Type -> Constraint) (b :: [Type]) Source #

Minimal complete definition

reduceVariant'

Instances

Instances details
ReduceVariant c ('[] :: [Type]) Source # 
Instance details

Defined in Data.Variant

Methods

reduceVariant' :: (forall a. c a => a -> r) -> Word -> (Any :: Type) -> r

(ReduceVariant c xs, c x) => ReduceVariant c (x ': xs) Source # 
Instance details

Defined in Data.Variant

Methods

reduceVariant' :: (forall a. c a => a -> r) -> Word -> (Any :: Type) -> r

Conversions between variants

appendVariant :: forall (ys :: [Type]) (xs :: [Type]). V xs -> V (Concat xs ys) Source #

Extend a variant by appending other possible values

prependVariant :: forall (ys :: [Type]) (xs :: [Type]). KnownNat (Length ys) => V xs -> V (Concat ys xs) Source #

Extend a variant by prepending other possible values

liftVariant :: forall (ys :: [Type]) (xs :: [Type]). LiftVariant xs ys => V xs -> V ys Source #

Lift a variant into another

Set values to the first matching type

nubVariant :: forall (xs :: [Type]). LiftVariant xs (Nub xs) => V xs -> V (Nub xs) Source #

Nub the type list

productVariant :: forall (xs :: [Type]) (ys :: [Type]). KnownNat (Length ys) => V xs -> V ys -> V (Product xs ys) Source #

Product of two variants

flattenVariant :: forall (xs :: [Type]). Flattenable (V xs) (V (FlattenVariant xs)) => V xs -> V (FlattenVariant xs) Source #

Flatten variants in a variant

joinVariant :: JoinVariant m xs => V xs -> m (V (ExtractM m xs)) Source #

Join on a variant

Transform a variant of applicatives as follow: f :: V [m a, m b, m c] -> m (V [a,b,c]) f = joinVariant @m

joinVariantUnsafe :: forall m (xs :: [Type]) (ys :: [Type]). (Functor m, ys ~ ExtractM m xs) => V xs -> m (V ys) Source #

Join on a variant in an unsafe way.

Works with IO for example but not with Maybe.

splitVariant :: forall (as :: [Type]) (xs :: [Type]). SplitVariant as (Complement xs as) xs => V xs -> Either (V (Complement xs as)) (V as) Source #

Split a variant in two

type LiftVariant (xs :: [Type]) (ys :: [Type]) = (LiftVariant' xs ys, xs :<< ys) Source #

xs is liftable in ys

class Flattenable a rs Source #

Minimal complete definition

toFlattenVariant

Instances

Instances details
Flattenable (V ('[] :: [Type])) rs Source # 
Instance details

Defined in Data.Variant

Methods

toFlattenVariant :: Word -> V ('[] :: [Type]) -> rs

(Flattenable (V ys) (V rs), KnownNat (Length xs)) => Flattenable (V (V xs ': ys)) (V rs) Source # 
Instance details

Defined in Data.Variant

Methods

toFlattenVariant :: Word -> V (V xs ': ys) -> V rs

type family FlattenVariant (xs :: [Type]) :: [Type] where ... Source #

Equations

FlattenVariant ('[] :: [Type]) = '[] :: [Type] 
FlattenVariant (V xs ': ys) = Concat xs (FlattenVariant ys) 
FlattenVariant (y ': ys) = y ': FlattenVariant ys 

type family ExtractM (m :: Type -> Type) (f :: [Type]) :: [Type] where ... Source #

Equations

ExtractM m ('[] :: [Type]) = '[] :: [Type] 
ExtractM m (m x ': xs) = x ': ExtractM m xs 

class JoinVariant (m :: Type -> Type) (xs :: [Type]) Source #

Minimal complete definition

joinVariant

Instances

Instances details
JoinVariant m ('[] :: [Type]) Source # 
Instance details

Defined in Data.Variant

Methods

joinVariant :: V ('[] :: [Type]) -> m (V (ExtractM m ('[] :: [Type]))) Source #

(Functor m, ExtractM m (m a ': xs) ~ (a ': ExtractM m xs), JoinVariant m xs) => JoinVariant m (m a ': xs) Source # 
Instance details

Defined in Data.Variant

Methods

joinVariant :: V (m a ': xs) -> m (V (ExtractM m (m a ': xs))) Source #

class SplitVariant (as :: [Type]) (rs :: [Type]) (xs :: [Type]) Source #

Minimal complete definition

splitVariant'

Instances

Instances details
SplitVariant as rs ('[] :: [Type]) Source # 
Instance details

Defined in Data.Variant

Methods

splitVariant' :: V ('[] :: [Type]) -> Either (V rs) (V as)

(n ~ MaybeIndexOf x as, m ~ MaybeIndexOf x rs, SplitVariant as rs xs, KnownNat m, KnownNat n) => SplitVariant as rs (x ': xs) Source # 
Instance details

Defined in Data.Variant

Methods

splitVariant' :: V (x ': xs) -> Either (V rs) (V as)

Conversions to/from other data types

variantToValue :: V '[a] -> a Source #

Retrieve a single value

variantFromValue :: a -> V '[a] Source #

Create a variant from a single value

variantToEither :: V '[a, b] -> Either b a Source #

Convert a variant of two values in a Either

variantFromEither :: Either a b -> V '[b, a] Source #

Lift an Either into a Variant (reversed order by convention)

Continuations

class ContVariant (xs :: [Type]) where Source #

Methods

variantToCont :: V xs -> ContFlow xs r Source #

Convert a variant into a multi-continuation

variantToContM :: Monad m => m (V xs) -> ContFlow xs (m r) Source #

Convert a variant into a multi-continuation

contToVariant :: ContFlow xs (V xs) -> V xs Source #

Convert a multi-continuation into a Variant

contToVariantM :: Monad m => ContFlow xs (m (V xs)) -> m (V xs) Source #

Convert a multi-continuation into a Variant

Instances

Instances details
ContVariant '[a, b, c, d, e, f, g, h, i, j, k, l] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a, b, c, d, e, f, g, h, i, j, k, l] -> ContFlow '[a, b, c, d, e, f, g, h, i, j, k, l] r Source #

variantToContM :: Monad m => m (V '[a, b, c, d, e, f, g, h, i, j, k, l]) -> ContFlow '[a, b, c, d, e, f, g, h, i, j, k, l] (m r) Source #

contToVariant :: ContFlow '[a, b, c, d, e, f, g, h, i, j, k, l] (V '[a, b, c, d, e, f, g, h, i, j, k, l]) -> V '[a, b, c, d, e, f, g, h, i, j, k, l] Source #

contToVariantM :: Monad m => ContFlow '[a, b, c, d, e, f, g, h, i, j, k, l] (m (V '[a, b, c, d, e, f, g, h, i, j, k, l])) -> m (V '[a, b, c, d, e, f, g, h, i, j, k, l]) Source #

ContVariant '[a, b, c, d, e, f, g, h, i, j, k] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a, b, c, d, e, f, g, h, i, j, k] -> ContFlow '[a, b, c, d, e, f, g, h, i, j, k] r Source #

variantToContM :: Monad m => m (V '[a, b, c, d, e, f, g, h, i, j, k]) -> ContFlow '[a, b, c, d, e, f, g, h, i, j, k] (m r) Source #

contToVariant :: ContFlow '[a, b, c, d, e, f, g, h, i, j, k] (V '[a, b, c, d, e, f, g, h, i, j, k]) -> V '[a, b, c, d, e, f, g, h, i, j, k] Source #

contToVariantM :: Monad m => ContFlow '[a, b, c, d, e, f, g, h, i, j, k] (m (V '[a, b, c, d, e, f, g, h, i, j, k])) -> m (V '[a, b, c, d, e, f, g, h, i, j, k]) Source #

ContVariant '[a, b, c, d, e, f, g, h, i, j] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a, b, c, d, e, f, g, h, i, j] -> ContFlow '[a, b, c, d, e, f, g, h, i, j] r Source #

variantToContM :: Monad m => m (V '[a, b, c, d, e, f, g, h, i, j]) -> ContFlow '[a, b, c, d, e, f, g, h, i, j] (m r) Source #

contToVariant :: ContFlow '[a, b, c, d, e, f, g, h, i, j] (V '[a, b, c, d, e, f, g, h, i, j]) -> V '[a, b, c, d, e, f, g, h, i, j] Source #

contToVariantM :: Monad m => ContFlow '[a, b, c, d, e, f, g, h, i, j] (m (V '[a, b, c, d, e, f, g, h, i, j])) -> m (V '[a, b, c, d, e, f, g, h, i, j]) Source #

ContVariant '[a, b, c, d, e, f, g, h, i] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a, b, c, d, e, f, g, h, i] -> ContFlow '[a, b, c, d, e, f, g, h, i] r Source #

variantToContM :: Monad m => m (V '[a, b, c, d, e, f, g, h, i]) -> ContFlow '[a, b, c, d, e, f, g, h, i] (m r) Source #

contToVariant :: ContFlow '[a, b, c, d, e, f, g, h, i] (V '[a, b, c, d, e, f, g, h, i]) -> V '[a, b, c, d, e, f, g, h, i] Source #

contToVariantM :: Monad m => ContFlow '[a, b, c, d, e, f, g, h, i] (m (V '[a, b, c, d, e, f, g, h, i])) -> m (V '[a, b, c, d, e, f, g, h, i]) Source #

ContVariant '[a, b, c, d, e, f, g, h] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a, b, c, d, e, f, g, h] -> ContFlow '[a, b, c, d, e, f, g, h] r Source #

variantToContM :: Monad m => m (V '[a, b, c, d, e, f, g, h]) -> ContFlow '[a, b, c, d, e, f, g, h] (m r) Source #

contToVariant :: ContFlow '[a, b, c, d, e, f, g, h] (V '[a, b, c, d, e, f, g, h]) -> V '[a, b, c, d, e, f, g, h] Source #

contToVariantM :: Monad m => ContFlow '[a, b, c, d, e, f, g, h] (m (V '[a, b, c, d, e, f, g, h])) -> m (V '[a, b, c, d, e, f, g, h]) Source #

ContVariant '[a, b, c, d, e, f, g] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a, b, c, d, e, f, g] -> ContFlow '[a, b, c, d, e, f, g] r Source #

variantToContM :: Monad m => m (V '[a, b, c, d, e, f, g]) -> ContFlow '[a, b, c, d, e, f, g] (m r) Source #

contToVariant :: ContFlow '[a, b, c, d, e, f, g] (V '[a, b, c, d, e, f, g]) -> V '[a, b, c, d, e, f, g] Source #

contToVariantM :: Monad m => ContFlow '[a, b, c, d, e, f, g] (m (V '[a, b, c, d, e, f, g])) -> m (V '[a, b, c, d, e, f, g]) Source #

ContVariant '[a, b, c, d, e, f] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a, b, c, d, e, f] -> ContFlow '[a, b, c, d, e, f] r Source #

variantToContM :: Monad m => m (V '[a, b, c, d, e, f]) -> ContFlow '[a, b, c, d, e, f] (m r) Source #

contToVariant :: ContFlow '[a, b, c, d, e, f] (V '[a, b, c, d, e, f]) -> V '[a, b, c, d, e, f] Source #

contToVariantM :: Monad m => ContFlow '[a, b, c, d, e, f] (m (V '[a, b, c, d, e, f])) -> m (V '[a, b, c, d, e, f]) Source #

ContVariant '[a, b, c, d, e] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a, b, c, d, e] -> ContFlow '[a, b, c, d, e] r Source #

variantToContM :: Monad m => m (V '[a, b, c, d, e]) -> ContFlow '[a, b, c, d, e] (m r) Source #

contToVariant :: ContFlow '[a, b, c, d, e] (V '[a, b, c, d, e]) -> V '[a, b, c, d, e] Source #

contToVariantM :: Monad m => ContFlow '[a, b, c, d, e] (m (V '[a, b, c, d, e])) -> m (V '[a, b, c, d, e]) Source #

ContVariant '[a, b, c, d] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a, b, c, d] -> ContFlow '[a, b, c, d] r Source #

variantToContM :: Monad m => m (V '[a, b, c, d]) -> ContFlow '[a, b, c, d] (m r) Source #

contToVariant :: ContFlow '[a, b, c, d] (V '[a, b, c, d]) -> V '[a, b, c, d] Source #

contToVariantM :: Monad m => ContFlow '[a, b, c, d] (m (V '[a, b, c, d])) -> m (V '[a, b, c, d]) Source #

ContVariant '[a, b, c] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a, b, c] -> ContFlow '[a, b, c] r Source #

variantToContM :: Monad m => m (V '[a, b, c]) -> ContFlow '[a, b, c] (m r) Source #

contToVariant :: ContFlow '[a, b, c] (V '[a, b, c]) -> V '[a, b, c] Source #

contToVariantM :: Monad m => ContFlow '[a, b, c] (m (V '[a, b, c])) -> m (V '[a, b, c]) Source #

ContVariant '[a, b] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a, b] -> ContFlow '[a, b] r Source #

variantToContM :: Monad m => m (V '[a, b]) -> ContFlow '[a, b] (m r) Source #

contToVariant :: ContFlow '[a, b] (V '[a, b]) -> V '[a, b] Source #

contToVariantM :: Monad m => ContFlow '[a, b] (m (V '[a, b])) -> m (V '[a, b]) Source #

ContVariant '[a] Source # 
Instance details

Defined in Data.Variant

Methods

variantToCont :: V '[a] -> ContFlow '[a] r Source #

variantToContM :: Monad m => m (V '[a]) -> ContFlow '[a] (m r) Source #

contToVariant :: ContFlow '[a] (V '[a]) -> V '[a] Source #

contToVariantM :: Monad m => ContFlow '[a] (m (V '[a])) -> m (V '[a]) Source #

Internals

pattern VSilent :: (Member c cs, PopVariant c cs) => c -> V cs Source #

Silent pattern synonym for Variant

Usage: case v of VSilent (x :: Int) -> ... VSilent (x :: String) -> ...

liftVariant' :: LiftVariant' xs ys => V xs -> V ys Source #

fromVariant' :: forall a (xs :: [Type]). PopVariant a xs => V xs -> Maybe a Source #

Try to a get a value of a given type from a Variant (silent)

popVariant' :: PopVariant a xs => V xs -> Either (V (Remove a xs)) a Source #

Remove a type from a variant

toVariant' :: forall a (l :: [Type]). Member a l => a -> V l Source #

Put a value into a Variant (silent)

Use the first matching type index.

class LiftVariant' (xs :: [Type]) (ys :: [Type]) Source #

xs is liftable in ys

Minimal complete definition

liftVariant'

Instances

Instances details
LiftVariant' ('[] :: [Type]) ys Source # 
Instance details

Defined in Data.Variant

Methods

liftVariant' :: V ('[] :: [Type]) -> V ys Source #

(LiftVariant' xs ys, KnownNat (IndexOf x ys)) => LiftVariant' (x ': xs) ys Source # 
Instance details

Defined in Data.Variant

Methods

liftVariant' :: V (x ': xs) -> V ys Source #

class PopVariant a (xs :: [Type]) Source #

Minimal complete definition

popVariant'

Instances

Instances details
PopVariant a ('[] :: [Type]) Source # 
Instance details

Defined in Data.Variant

Methods

popVariant' :: V ('[] :: [Type]) -> Either (V (Remove a ('[] :: [Type]))) a Source #

(PopVariant a xs', n ~ MaybeIndexOf a xs, xs' ~ RemoveAt1 n xs, Remove a xs' ~ Remove a xs, KnownNat n, xs ~ (y ': ys)) => PopVariant a (y ': ys) Source # 
Instance details

Defined in Data.Variant

Methods

popVariant' :: V (y ': ys) -> Either (V (Remove a (y ': ys))) a Source #

class ToVariantMaybe a (xs :: [Type]) where Source #

Put a value into a variant if possible

>>> toVariantMaybe "Test" :: Maybe (V [Int,Float])
Nothing
>>> toVariantMaybe "Test" :: Maybe (V [Int,Float,String])
Just "Test"

Methods

toVariantMaybe :: a -> Maybe (V xs) Source #

Put a value into a Variant, when the Variant's row contains that type.

Instances

Instances details
ToVariantMaybe a ('[] :: [Type]) Source # 
Instance details

Defined in Data.Variant

Methods

toVariantMaybe :: a -> Maybe (V ('[] :: [Type])) Source #

(n ~ MaybeIndexOf a xs, KnownNat n, xs ~ (y ': ys)) => ToVariantMaybe a (y ': ys) Source # 
Instance details

Defined in Data.Variant

Methods

toVariantMaybe :: a -> Maybe (V (y ': ys)) Source #

showsVariant :: forall (xs :: [Type]). (Typeable xs, ShowTypeList (V xs), ShowVariantValue (V xs)) => Int -> V xs -> ShowS Source #

Haskell code corresponding to a Variant

>>> showsVariant 0 (V @Double 5.0 :: V [Int,String,Double]) ""
"V @Double 5.0 :: V [Int, [Char], Double]"