data-diverse-0.1.0.0: Extensible records and polymorphic variants.

Safe HaskellNone
LanguageHaskell2010

Data.Diverse.Which.Internal

Contents

Synopsis

Which type

data Which xs Source #

A Which is an anonymous sum type (also known as a polymorphic variant, or co-record) which can only contain one of the types in the typelist. This is essentially a typed version of Dynamic.

The following functions are available can be used to manipulate unique types in the typelist

These functions are type specified. This means labels are not required because the types themselves can be used to access the Which. It is a compile error to use those functions for duplicate fields.

For duplicate types in the list of possible types, Nat-indexed version of the functions are available:

Encoding: The variant contains a value whose type is at the given position in the type list. This is the same encoding as Haskus.Util.Variant and Data.Hlist.Variant.

The constructor is only exported in the Data.Diverse.Which.Internal module

Constructors

Which !Int Any 

Instances

Case c ((:) Type x ([] Type)) r => Reduce Which (Switch c) ((:) Type x ([] Type)) r Source #

Terminating case of the loop, ensuring that a instance of Case '[] with an empty typelist is not required. You can't reduce impossible

Methods

reduce :: Switch c ((Type ': x) [Type]) r -> Which ((Type ': x) [Type]) -> r Source #

(Case c ((:) Type x ((:) Type x' xs)) r, Reduce Which (Switch c) ((:) Type x' xs) r, Reiterate * c ((:) Type x ((:) Type x' xs))) => Reduce Which (Switch c) ((:) Type x ((:) Type x' xs)) r Source #

trial0 each type in a Which, and either handle the case' with value discovered, or reiterate trying the next type in the type list. This code will be efficiently compiled into a single case statement in GHC 8.2.1 See http://hsyl20.fr/home/posts/2016-12-12-control-flow-in-haskell-part-2.html

Methods

reduce :: Switch c ((Type ': x) ((Type ': x') xs)) r -> Which ((Type ': x) ((Type ': x') xs)) -> r Source #

Case (c n) ((:) Type x ([] Type)) r => Reduce Which (SwitchN c n) ((:) Type x ([] Type)) r Source #

Terminating case of the loop, ensuring that a instance of Case '[] with an empty typelist is not required. You can't reduce impossible

Methods

reduce :: SwitchN c n ((Type ': x) [Type]) r -> Which ((Type ': x) [Type]) -> r Source #

(Case (c n) ((:) Type x ((:) Type x' xs)) r, Reduce Which (SwitchN c ((+) n 1)) ((:) Type x' xs) r, ReiterateN * c n ((:) Type x ((:) Type x' xs))) => Reduce Which (SwitchN c n) ((:) Type x ((:) Type x' xs)) r Source #

trial0 each type in a Which, and either handle the case' with value discovered, or reiterateN trying the next type in the type list. This code will be efficiently compiled into a single case statement in GHC 8.2.1 See http://hsyl20.fr/home/posts/2016-12-12-control-flow-in-haskell-part-2.html

Methods

reduce :: SwitchN c n ((Type ': x) ((Type ': x') xs)) r -> Which ((Type ': x) ((Type ': x') xs)) -> r Source #

Reduce Which (Switch CaseEqWhich) ((:) Type x xs) Bool => Eq (Which ((:) Type x xs)) Source #

Two Whiches are only equal iff they both contain the equivalnet value at the same type index.

Methods

(==) :: Which ((Type ': x) xs) -> Which ((Type ': x) xs) -> Bool #

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

Eq (Which ([] Type)) Source #
(impossible == impossible) == True

Methods

(==) :: Which [Type] -> Which [Type] -> Bool #

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

(Reduce Which (Switch CaseEqWhich) ((:) Type x xs) Bool, Reduce Which (Switch CaseOrdWhich) ((:) Type x xs) Ordering) => Ord (Which ((:) Type x xs)) Source #

A Which with a type at smaller type index is considered smaller.

Methods

compare :: Which ((Type ': x) xs) -> Which ((Type ': x) xs) -> Ordering #

(<) :: Which ((Type ': x) xs) -> Which ((Type ': x) xs) -> Bool #

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

(>) :: Which ((Type ': x) xs) -> Which ((Type ': x) xs) -> Bool #

(>=) :: Which ((Type ': x) xs) -> Which ((Type ': x) xs) -> Bool #

max :: Which ((Type ': x) xs) -> Which ((Type ': x) xs) -> Which ((Type ': x) xs) #

min :: Which ((Type ': x) xs) -> Which ((Type ': x) xs) -> Which ((Type ': x) xs) #

Ord (Which ([] Type)) Source #
(compare impossible impossible) == EQ

Methods

compare :: Which [Type] -> Which [Type] -> Ordering #

(<) :: Which [Type] -> Which [Type] -> Bool #

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

(>) :: Which [Type] -> Which [Type] -> Bool #

(>=) :: Which [Type] -> Which [Type] -> Bool #

max :: Which [Type] -> Which [Type] -> Which [Type] #

min :: Which [Type] -> Which [Type] -> Which [Type] #

AFoldable (Collector * EmitReadWhich ((:) Type x xs)) (ReadPrec (Int, WrappedAny)) => Read (Which ((:) Type x xs)) Source #

This Read instance tries to read using the each type in the typelist, using the first successful type read.

Methods

readsPrec :: Int -> ReadS (Which ((Type ': x) xs)) #

readList :: ReadS [Which ((Type ': x) xs)] #

readPrec :: ReadPrec (Which ((Type ': x) xs)) #

readListPrec :: ReadPrec [Which ((Type ': x) xs)] #

Read (Which ([] Type)) Source #
read "impossible" == impossible
Reduce Which (Switch CaseShowWhich) ((:) Type x xs) ShowS => Show (Which ((:) Type x xs)) Source #
show (pick' 'A') == "pick 'A'"

Methods

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

show :: Which ((Type ': x) xs) -> String #

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

Show (Which ([] Type)) Source #
read "impossible" == impossible

Methods

showsPrec :: Int -> Which [Type] -> ShowS #

show :: Which [Type] -> String #

showList :: [Which [Type]] -> ShowS #

Generic (Which ((:) Type x ((:) Type x' xs))) Source #

A Generic instance encoded as either the x value (:+:) or the diversify0ed remaining 'Which xs'. The C1 and S1 metadata are not encoded.

Associated Types

type Rep (Which ((:) Type x ((:) Type x' xs))) :: * -> * #

Methods

from :: Which ((Type ': x) ((Type ': x') xs)) -> Rep (Which ((Type ': x) ((Type ': x') xs))) x #

to :: Rep (Which ((Type ': x) ((Type ': x') xs))) x -> Which ((Type ': x) ((Type ': x') xs)) #

Generic (Which ((:) Type x ([] Type))) Source #

A terminating Generic instance for one type encoded with pick'. The C1 and S1 metadata are not encoded.

Associated Types

type Rep (Which ((:) Type x ([] Type))) :: * -> * #

Methods

from :: Which ((Type ': x) [Type]) -> Rep (Which ((Type ': x) [Type])) x #

to :: Rep (Which ((Type ': x) [Type])) x -> Which ((Type ': x) [Type]) #

Generic (Which ([] Type)) Source #

A terminating Generic instance for no types encoded as a impossible. The C1 and S1 metadata are not encoded.

Associated Types

type Rep (Which ([] Type)) :: * -> * #

Methods

from :: Which [Type] -> Rep (Which [Type]) x #

to :: Rep (Which [Type]) x -> Which [Type] #

type Rep (Which ((:) Type x ((:) Type x' xs))) Source # 
type Rep (Which ((:) Type x ((:) Type x' xs))) = D1 (MetaData "Which" "Data.Diverse.Which.Internal" PackageId False) ((:+:) (Rec0 x) (Rec0 (Which ((:) Type x' xs))))
type Rep (Which ((:) Type x ([] Type))) Source # 
type Rep (Which ((:) Type x ([] Type))) = D1 (MetaData "Which" "Data.Diverse.Which.Internal" PackageId False) (Rec0 x)
type Rep (Which ([] Type)) Source # 
type Rep (Which ([] Type)) = D1 (MetaData "Which" "Data.Diverse.Which.Internal" PackageId False) U1

Single type

Construction

impossible :: Which '[] Source #

A Which with no alternatives. You can't do anything with impossible except Eq, Read, and Show it. Using functions like switch and trial with impossible is a compile error. impossible is only useful as a Left-over from trialing a Which '[x] with one type.

pick :: forall xs x. UniqueMember x xs => x -> Which xs Source #

Lift a value into a Which of possibly other types xs. xs can be inferred or specified with TypeApplications. NB. forall is used to specify xs first, so TypeApplications can be used to specify xs first

pick 'A' @'[Int, Bool, Char, Maybe String] :: Which '[Int, Bool, Char, Maybe String]

pick0 :: x -> Which (x ': xs) Source #

A variation of pick into a Which where x is the first type.

pick0 'A' :: Which '[Char, Int, Bool]

pickOnly :: x -> Which '[x] Source #

A variation of pick into a Which of a single type.

pickOnly 'A' :: Which '[Char]

pickN :: forall n xs x proxy. MemberAt n x xs => proxy n -> x -> Which xs Source #

Lift a value into a Which of possibly other (possibley indistinct) types, where the value is the n-th type.

pickN (Proxy @4) (5 :: Int) :: Which '[Bool, Int, Char, Bool, Int, Char]

Destruction

obvious :: Which '[a] -> a Source #

It is obvious what value is inside a Which of one type.

let x = pick' 'A' :: Which '[Char]
obvious x `shouldBe` 'A'

trial :: forall x xs. UniqueMember x xs => Which xs -> Either (Which (Without x xs)) x Source #

trial a type in a Which and Either get the Right value or the Left-over possibilities.

let x = pick 'A' @'[Int, Bool, Char, Maybe String] :: Which '[Int, Bool, Char, Maybe String]
trial @Char x `shouldBe` Right 'A'
trial @Int x `shouldBe` Left (pick 'A') :: Which '[Bool, Char, Maybe String]

trial0 :: Which (x ': xs) -> Either (Which xs) x Source #

A variation of a Which trial which trials the first type in the type list.

let x = pick 'A' @'[Int, Bool, Char, Maybe String] :: Which '[Int, Bool, Char, Maybe String]
trial0 x `shouldBe` Left (pick 'A') :: Which '[Bool, Char, Maybe String]

trialN :: forall n xs x proxy. MemberAt n x xs => proxy n -> Which xs -> Either (Which (WithoutIndex n xs)) x Source #

trialN the n-th type of a Which, and get Either the Right value or the Left-over possibilities.

let x = pick 'A' @'[Int, Bool, Char, Maybe String] :: Which '[Int, Bool, Char, Maybe String]
trialN @1 Proxy x `shouldBe` Left (pick 'A') :: Which '[Int, Char, Maybe String]

Lens

facet :: forall x xs. UniqueMember x xs => Prism' (Which xs) x Source #

pick (review facet) and trial (preview facet) in Prism' form.

facet = prism' pick (either (const Nothing) Just . trial)
let y = review (facet @Int) (5 :: Int) :: Which '[Bool, Int, Char, Bool, Char] -- pick
    x = preview (facet @Int) y -- trial
x `shouldBe` (Just 5)

facetN :: forall n xs x proxy. MemberAt n x xs => proxy n -> Prism' (Which xs) x Source #

pickN (review facetN) and trialN (preview facetN) in Prism' form.

facetN p = prism' (pickN p) (either (const Nothing) Just . trialN p)
let y = review (facetN (Proxy @4)) (5 :: Int) :: Which '[Bool, Int, Char, Bool, Int, Char] -- pickN
    x = preview (facetN (Proxy @4)) y -- trialN
x `shouldBe` (Just 5)

Multiple types

Injection

type Diversify tree branch = Reduce Which (Switch (CaseDiversify tree branch)) branch (Which tree) Source #

A friendlier constraint synonym for diversify.

diversify :: forall tree branch. Diversify tree branch => Which branch -> Which tree Source #

Convert a Which to another Which that may include other possibilities. That is, branch is equal or is a subset of tree.

This can also be used to rearrange the order of the types in the Which.

It is a compile error if tree has duplicate types with branch.

NB. forall is used to tree is ordered first, so TypeApplications can be used to specify tree first.

let a = pick' (5 :: Int) :: Which '[Int]
    b = diversify @[Int, Bool] a :: Which '[Int, Bool]
    c = diversify @[Bool, Int] b :: Which '[Bool, Int]

diversify0 :: proxy x -> Which xs -> Which (x ': xs) Source #

A simple version of diversify which add another type to the front of the typelist.

type DiversifyN indices tree branch = (Reduce Which (SwitchN (CaseDiversifyN indices) 0) (KindsAtIndices indices tree) (Which tree), KindsAtIndices indices tree ~ branch) Source #

A friendlier constraint synonym for diversifyN.

diversifyN :: forall indices tree branch proxy. DiversifyN indices tree branch => proxy indices -> Which branch -> Which tree Source #

A variation of diversify which uses a Nat list n to specify how to reorder the fields, where

indices[branch_idx] = tree_idx@

This variation allows tree to contain duplicate types with branch since the mapping is specified by indicies.

let y = pickOnly (5 :: Int)
    y' = diversify @[Int, Bool] y
    y'' = diversify @[Bool, Int] y'
switch y'' (CaseTypeable (show . typeRep . (pure @Proxy))) `shouldBe` "Int"

Inverse Injection

type Reinterpret branch tree = Reduce Which (Switch (CaseReinterpret branch tree)) tree (Either (Which (Complement tree branch)) (Which branch)) Source #

A friendlier constraint synonym for reinterpret.

reinterpret :: forall branch tree. Reinterpret branch tree => Which tree -> Either (Which (Complement tree branch)) (Which branch) Source #

Convert a Which into possibly another Which with a totally different typelist. Returns either a Which with the Right value, or a Which with the Leftover compliment types.

It is a compile error if branch or compliment has duplicate types with tree.

NB. forall used to specify branch first, so TypeApplications can be used to specify branch first.

    let a = pick @[Int, Char, Bool] (5 :: Int) :: Which '[Int, Char, Bool]
    let  b = reinterpret [String, Char] y
    b `shouldBe` Left (pick (5 :: Int)) :: Which '[Int, Bool]
    let c = reinterpret [String, Int] a
    c `shouldBe` Right (pick (5 :: Int)) :: Which '[String, Int]

type ReinterpretN indices branch tree = (Reduce Which (SwitchN (CaseReinterpretN indices) 0) tree (Maybe (Which (KindsAtIndices indices tree))), KindsAtIndices indices tree ~ branch) Source #

A friendlier constraint synonym for reinterpretN.

reinterpretN :: forall indices branch tree proxy. ReinterpretN indices branch tree => proxy indices -> Which tree -> Maybe (Which branch) Source #

A limited variation of reinterpret which uses a Nat list n to specify how to reorder the fields, where

indices[branch_idx] = tree_idx@

This variation allows tree to contain duplicate types with branch since the mapping is specified by indicies.

However, unlike reinterpert, in this variation, branch must be a subset of tree instead of any arbitrary Which. Also it returns a Maybe instead of Either.

This is so that the same indices can be used in narrowN.

Lens

inject :: forall branch tree. (Diversify tree branch, Reinterpret branch tree) => Prism' (Which tree) (Which branch) Source #

diversify (review inject) and reinterpret (preview inject) in Prism' form.

let x = pick (5 :: Int) :: Which '[String, Int]
    y = review (inject @_ @[Bool, Int, Char, String]) x -- diversify
y `shouldBe` pick (5 :: Int) :: Which '[Bool, Int, Char, String]
let y' = preview (inject @[String, Int]) y -- reinterpret
y' `shouldBe` Just (pick (5 :: Int)) :: Maybe (Which '[String, Int])

injectN :: forall indices branch tree proxy. (DiversifyN indices tree branch, ReinterpretN indices branch tree) => proxy indices -> Prism' (Which tree) (Which branch) Source #

diversifyN (review injectN) and reinterpretN (preview injectN) in Prism' form.

let x = pick (5 :: Int) :: Which '[String, Int]
    y = review (injectN @[3, 1] @_ @[Bool, Int, Char, String] Proxy) x -- diversifyN
y `shouldBe` pick (5 :: Int) :: Which '[Bool, Int, Char, String]
let y' = preview (injectN @[3, 1] @[String, Int] Proxy) y -- reinterpertN'
y' `shouldBe` Just (pick (5 :: Int)) :: Maybe (Which '[String, Int])

Catamorphism

newtype Switch c xs r Source #

Switch is an instance of Reduce for which reiterates through the possibilities in a Which, delegating handling to Case, ensuring termination when Which only contains one type.

Constructors

Switch (c xs r) 

Instances

Case c ((:) Type x ([] Type)) r => Reduce Which (Switch c) ((:) Type x ([] Type)) r Source #

Terminating case of the loop, ensuring that a instance of Case '[] with an empty typelist is not required. You can't reduce impossible

Methods

reduce :: Switch c ((Type ': x) [Type]) r -> Which ((Type ': x) [Type]) -> r Source #

(Case c ((:) Type x ((:) Type x' xs)) r, Reduce Which (Switch c) ((:) Type x' xs) r, Reiterate * c ((:) Type x ((:) Type x' xs))) => Reduce Which (Switch c) ((:) Type x ((:) Type x' xs)) r Source #

trial0 each type in a Which, and either handle the case' with value discovered, or reiterate trying the next type in the type list. This code will be efficiently compiled into a single case statement in GHC 8.2.1 See http://hsyl20.fr/home/posts/2016-12-12-control-flow-in-haskell-part-2.html

Methods

reduce :: Switch c ((Type ': x) ((Type ': x') xs)) r -> Which ((Type ': x) ((Type ': x') xs)) -> r Source #

which :: Reduce Which (Switch case') xs r => case' xs r -> Which xs -> r Source #

Catamorphism for Which. This is equivalent to flip switch.

switch :: Reduce Which (Switch case') xs r => Which xs -> case' xs r -> r Source #

A switch/case statement for Which. This is equivalent to flip which

Use Case instances like Cases to apply a Which of functions to a variant of values.

let y = pick (5 :: Int) :: Which '[Int, Bool]
switch y (
    cases (show @Bool
        ./ show @Int
        ./ nul)) `shouldBe` "5"

Or CaseTypeable to apply a polymorphic function that work on all Typeables.

let y = pick (5 :: Int) :: Which '[Int, Bool]
switch y (CaseTypeable (show . typeRep . (pure @Proxy))) `shouldBe` Int

Or you may use your own custom instance of Case.

newtype SwitchN c n xs r Source #

SwitchN is a variation of Switch which reiterateNs through the possibilities in a Which, delegating work to CaseN, ensuring termination when Which only contains one type.

Constructors

SwitchN (c n xs r) 

Instances

Case (c n) ((:) Type x ([] Type)) r => Reduce Which (SwitchN c n) ((:) Type x ([] Type)) r Source #

Terminating case of the loop, ensuring that a instance of Case '[] with an empty typelist is not required. You can't reduce impossible

Methods

reduce :: SwitchN c n ((Type ': x) [Type]) r -> Which ((Type ': x) [Type]) -> r Source #

(Case (c n) ((:) Type x ((:) Type x' xs)) r, Reduce Which (SwitchN c ((+) n 1)) ((:) Type x' xs) r, ReiterateN * c n ((:) Type x ((:) Type x' xs))) => Reduce Which (SwitchN c n) ((:) Type x ((:) Type x' xs)) r Source #

trial0 each type in a Which, and either handle the case' with value discovered, or reiterateN trying the next type in the type list. This code will be efficiently compiled into a single case statement in GHC 8.2.1 See http://hsyl20.fr/home/posts/2016-12-12-control-flow-in-haskell-part-2.html

Methods

reduce :: SwitchN c n ((Type ': x) ((Type ': x') xs)) r -> Which ((Type ': x) ((Type ': x') xs)) -> r Source #

whichN :: Reduce Which (SwitchN case' n) xs r => case' n xs r -> Which xs -> r Source #

Catamorphism for Which. This is equivalent to flip switchN.

switchN :: Reduce Which (SwitchN case' n) xs r => Which xs -> case' n xs r -> r Source #

A switch/case statement for Which. This is equivalent to flip whichN

Use Case instances like CasesN to apply a Which of functions to a variant of values in index order.

let y = pickN @0 Proxy (5 :: Int) :: Which '[Int, Bool, Bool, Int]
switchN y (
    casesN (show @Int
        ./ show @Bool
        ./ show @Bool
        ./ show @Int
        ./ nul)) `shouldBe` "5"

Or you may use your own custom instance of Case.