Safe Haskell | None |
---|---|

Language | Haskell2010 |

Classes for generalized combinators on SOP types.

In the SOP approach to generic programming, we're predominantly concerned with four structured datatypes:

`NP`

:: (k -> *) -> ( [k] -> *) -- n-ary product`NS`

:: (k -> *) -> ( [k] -> *) -- n-ary sum`POP`

:: (k -> *) -> ([[k]] -> *) -- product of products`SOP`

:: (k -> *) -> ([[k]] -> *) -- sum of products

All of these have a kind that fits the following pattern:

(k -> *) -> (l -> *)

These four types support similar interfaces. In order to allow reusing the same combinator names for all of these types, we define various classes in this module that allow the necessary generalization.

The classes typically lift concepts that exist for kinds `*`

or
`* -> *`

to datatypes of kind `(k -> *) -> (l -> *)`

. This module
also derives a number of derived combinators.

The actual instances are defined in Generics.SOP.NP and Generics.SOP.NS.

- class HPure h where
- newtype (f -.-> g) a = Fn {
- apFn :: f a -> g a

- fn :: (f a -> f' a) -> (f -.-> f') a
- fn_2 :: (f a -> f' a -> f'' a) -> (f -.-> (f' -.-> f'')) a
- fn_3 :: (f a -> f' a -> f'' a -> f''' a) -> (f -.-> (f' -.-> (f'' -.-> f'''))) a
- fn_4 :: (f a -> f' a -> f'' a -> f''' a -> f'''' a) -> (f -.-> (f' -.-> (f'' -.-> (f''' -.-> f'''')))) a
- type family Prod (h :: (k -> *) -> l -> *) :: (k -> *) -> l -> *
- class (Prod (Prod h) ~ Prod h, HPure (Prod h)) => HAp h where
- hliftA :: (SListIN (Prod h) xs, HAp h) => (forall a. f a -> f' a) -> h f xs -> h f' xs
- hliftA2 :: (SListIN (Prod h) xs, HAp h, HAp (Prod h)) => (forall a. f a -> f' a -> f'' a) -> Prod h f xs -> h f' xs -> h f'' xs
- hliftA3 :: (SListIN (Prod h) xs, HAp h, HAp (Prod h)) => (forall a. f a -> f' a -> f'' a -> f''' a) -> Prod h f xs -> Prod h f' xs -> h f'' xs -> h f''' xs
- hmap :: (SListIN (Prod h) xs, HAp h) => (forall a. f a -> f' a) -> h f xs -> h f' xs
- hzipWith :: (SListIN (Prod h) xs, HAp h, HAp (Prod h)) => (forall a. f a -> f' a -> f'' a) -> Prod h f xs -> h f' xs -> h f'' xs
- hzipWith3 :: (SListIN (Prod h) xs, HAp h, HAp (Prod h)) => (forall a. f a -> f' a -> f'' a -> f''' a) -> Prod h f xs -> Prod h f' xs -> h f'' xs -> h f''' xs
- hcliftA :: (AllN (Prod h) c xs, HAp h) => proxy c -> (forall a. c a => f a -> f' a) -> h f xs -> h f' xs
- hcliftA2 :: (AllN (Prod h) c xs, HAp h, HAp (Prod h)) => proxy c -> (forall a. c a => f a -> f' a -> f'' a) -> Prod h f xs -> h f' xs -> h f'' xs
- hcliftA3 :: (AllN (Prod h) c xs, HAp h, HAp (Prod h)) => proxy c -> (forall a. c a => f a -> f' a -> f'' a -> f''' a) -> Prod h f xs -> Prod h f' xs -> h f'' xs -> h f''' xs
- hcmap :: (AllN (Prod h) c xs, HAp h) => proxy c -> (forall a. c a => f a -> f' a) -> h f xs -> h f' xs
- hczipWith :: (AllN (Prod h) c xs, HAp h, HAp (Prod h)) => proxy c -> (forall a. c a => f a -> f' a -> f'' a) -> Prod h f xs -> h f' xs -> h f'' xs
- hczipWith3 :: (AllN (Prod h) c xs, HAp h, HAp (Prod h)) => proxy c -> (forall a. c a => f a -> f' a -> f'' a -> f''' a) -> Prod h f xs -> Prod h f' xs -> h f'' xs -> h f''' xs
- type family CollapseTo (h :: (k -> *) -> l -> *) (x :: *) :: *
- class HCollapse h where
- class HAp h => HSequence h where
- hsequence :: (SListIN h xs, SListIN (Prod h) xs, HSequence h) => Applicative f => h f xs -> f (h I xs)
- hsequenceK :: (SListIN h xs, SListIN (Prod h) xs, Applicative f, HSequence h) => h (K (f a)) xs -> f (h (K a) xs)
- class HIndex h where
- type family UnProd (h :: (k -> *) -> l -> *) :: (k -> *) -> l -> *
- class UnProd (Prod h) ~ h => HApInjs h where
- class HExpand h where

# Generalized applicative functor structure

## Generalized `pure`

hpure :: SListIN h xs => (forall a. f a) -> h f xs Source #

Corresponds to `pure`

directly.

*Instances:*

`hpure`

,`pure_NP`

::`SListI`

xs => (forall a. f a) ->`NP`

f xs`hpure`

,`pure_POP`

::`SListI2`

xss => (forall a. f a) ->`POP`

f xss

hcpure :: AllN h c xs => proxy c -> (forall a. c a => f a) -> h f xs Source #

A variant of `hpure`

that allows passing in a constrained
argument.

Calling

where `hcpure`

f s`s :: h f xs`

causes `f`

to be
applied at all the types that are contained in `xs`

. Therefore,
the constraint `c`

has to be satisfied for all elements of `xs`

,
which is what

states.`AllMap`

h c xs

Morally, `hpure`

is a special case of `hcpure`

where the
constraint is empty. However, it is in the nature of how `AllMap`

is defined as well as current GHC limitations that it is tricky
to prove to GHC in general that

is
always satisfied. Therefore, we typically define `AllMap`

h c NoConstraint xs`hpure`

separately and directly, and make it a member of the class.

*Instances:*

`hcpure`

,`cpure_NP`

:: (`All`

c xs ) => proxy c -> (forall a. c a => f a) ->`NP`

f xs`hcpure`

,`cpure_POP`

:: (`All2`

c xss) => proxy c -> (forall a. c a => f a) ->`POP`

f xss

## Generalized `<*>`

fn :: (f a -> f' a) -> (f -.-> f') a Source #

Construct a lifted function.

Same as `Fn`

. Only available for uniformity with the
higher-arity versions.

fn_2 :: (f a -> f' a -> f'' a) -> (f -.-> (f' -.-> f'')) a Source #

Construct a binary lifted function.

fn_3 :: (f a -> f' a -> f'' a -> f''' a) -> (f -.-> (f' -.-> (f'' -.-> f'''))) a Source #

Construct a ternary lifted function.

fn_4 :: (f a -> f' a -> f'' a -> f''' a -> f'''' a) -> (f -.-> (f' -.-> (f'' -.-> (f''' -.-> f'''')))) a Source #

Construct a quarternary lifted function.

type family Prod (h :: (k -> *) -> l -> *) :: (k -> *) -> l -> * Source #

Maps a structure containing sums to the corresponding product structure.

class (Prod (Prod h) ~ Prod h, HPure (Prod h)) => HAp h where Source #

A generalization of `<*>`

.

hap :: Prod h (f -.-> g) xs -> h f xs -> h g xs Source #

Corresponds to `<*>`

.

For products (`NP`

) as well as products of products
(`POP`

), the correspondence is rather direct. We combine
a structure containing (lifted) functions and a compatible structure
containing corresponding arguments into a compatible structure
containing results.

The same combinator can also be used to combine a product structure of functions with a sum structure of arguments, which then results in another sum structure of results. The sum structure determines which part of the product structure will be used.

*Instances:*

`hap`

,`ap_NP`

::`NP`

(f -.-> g) xs ->`NP`

f xs ->`NP`

g xs`hap`

,`ap_NS`

::`NP`

(f -.-> g) xs ->`NS`

f xs ->`NS`

g xs`hap`

,`ap_POP`

::`POP`

(f -.-> g) xss ->`POP`

f xss ->`POP`

g xss`hap`

,`ap_SOP`

::`POP`

(f -.-> g) xss ->`SOP`

f xss ->`SOP`

g xss

## Derived functions

hliftA :: (SListIN (Prod h) xs, HAp h) => (forall a. f a -> f' a) -> h f xs -> h f' xs Source #

A generalized form of `liftA`

,
which in turn is a generalized `map`

.

Takes a lifted function and applies it to every element of a structure while preserving its shape.

*Specification:*

`hliftA`

f xs =`hpure`

(`fn`

f) ``hap`

` xs

*Instances:*

`hliftA`

,`liftA_NP`

::`SListI`

xs => (forall a. f a -> f' a) ->`NP`

f xs ->`NP`

f' xs`hliftA`

,`liftA_NS`

::`SListI`

xs => (forall a. f a -> f' a) ->`NS`

f xs ->`NS`

f' xs`hliftA`

,`liftA_POP`

::`SListI2`

xss => (forall a. f a -> f' a) ->`POP`

f xss ->`POP`

f' xss`hliftA`

,`liftA_SOP`

::`SListI2`

xss => (forall a. f a -> f' a) ->`SOP`

f xss ->`SOP`

f' xss

hliftA2 :: (SListIN (Prod h) xs, HAp h, HAp (Prod h)) => (forall a. f a -> f' a -> f'' a) -> Prod h f xs -> h f' xs -> h f'' xs Source #

A generalized form of `liftA2`

,
which in turn is a generalized `zipWith`

.

Takes a lifted binary function and uses it to combine two structures of equal shape into a single structure.

It either takes two product structures to a product structure, or one product and one sum structure to a sum structure.

*Specification:*

`hliftA2`

f xs ys =`hpure`

(`fn_2`

f) ``hap`

` xs ``hap`

` ys

*Instances:*

`hliftA2`

,`liftA2_NP`

::`SListI`

xs => (forall a. f a -> f' a -> f'' a) ->`NP`

f xs ->`NP`

f' xs ->`NP`

f'' xs`hliftA2`

,`liftA2_NS`

::`SListI`

xs => (forall a. f a -> f' a -> f'' a) ->`NP`

f xs ->`NS`

f' xs ->`NS`

f'' xs`hliftA2`

,`liftA2_POP`

::`SListI2`

xss => (forall a. f a -> f' a -> f'' a) ->`POP`

f xss ->`POP`

f' xss ->`POP`

f'' xss`hliftA2`

,`liftA2_SOP`

::`SListI2`

xss => (forall a. f a -> f' a -> f'' a) ->`POP`

f xss ->`SOP`

f' xss ->`SOP`

f'' xss

hliftA3 :: (SListIN (Prod h) xs, HAp h, HAp (Prod h)) => (forall a. f a -> f' a -> f'' a -> f''' a) -> Prod h f xs -> Prod h f' xs -> h f'' xs -> h f''' xs Source #

A generalized form of `liftA3`

,
which in turn is a generalized `zipWith3`

.

Takes a lifted ternary function and uses it to combine three structures of equal shape into a single structure.

It either takes three product structures to a product structure, or two product structures and one sum structure to a sum structure.

*Specification:*

`hliftA3`

f xs ys zs =`hpure`

(`fn_3`

f) ``hap`

` xs ``hap`

` ys ``hap`

` zs

*Instances:*

`hliftA3`

,`liftA3_NP`

::`SListI`

xs => (forall a. f a -> f' a -> f'' a -> f''' a) ->`NP`

f xs ->`NP`

f' xs ->`NP`

f'' xs ->`NP`

f''' xs`hliftA3`

,`liftA3_NS`

::`SListI`

xs => (forall a. f a -> f' a -> f'' a -> f''' a) ->`NP`

f xs ->`NP`

f' xs ->`NS`

f'' xs ->`NS`

f''' xs`hliftA3`

,`liftA3_POP`

::`SListI2`

xss => (forall a. f a -> f' a -> f'' a -> f''' a) ->`POP`

f xss ->`POP`

f' xss ->`POP`

f'' xss ->`POP`

f''' xs`hliftA3`

,`liftA3_SOP`

::`SListI2`

xss => (forall a. f a -> f' a -> f'' a -> f''' a) ->`POP`

f xss ->`POP`

f' xss ->`SOP`

f'' xss ->`SOP`

f''' xs

hmap :: (SListIN (Prod h) xs, HAp h) => (forall a. f a -> f' a) -> h f xs -> h f' xs Source #

Another name for `hliftA`

.

*Since: 0.2*

hzipWith :: (SListIN (Prod h) xs, HAp h, HAp (Prod h)) => (forall a. f a -> f' a -> f'' a) -> Prod h f xs -> h f' xs -> h f'' xs Source #

Another name for `hliftA2`

.

*Since: 0.2*

hzipWith3 :: (SListIN (Prod h) xs, HAp h, HAp (Prod h)) => (forall a. f a -> f' a -> f'' a -> f''' a) -> Prod h f xs -> Prod h f' xs -> h f'' xs -> h f''' xs Source #

Another name for `hliftA3`

.

*Since: 0.2*

hcliftA :: (AllN (Prod h) c xs, HAp h) => proxy c -> (forall a. c a => f a -> f' a) -> h f xs -> h f' xs Source #

hcliftA2 :: (AllN (Prod h) c xs, HAp h, HAp (Prod h)) => proxy c -> (forall a. c a => f a -> f' a -> f'' a) -> Prod h f xs -> h f' xs -> h f'' xs Source #

hcliftA3 :: (AllN (Prod h) c xs, HAp h, HAp (Prod h)) => proxy c -> (forall a. c a => f a -> f' a -> f'' a -> f''' a) -> Prod h f xs -> Prod h f' xs -> h f'' xs -> h f''' xs Source #

hcmap :: (AllN (Prod h) c xs, HAp h) => proxy c -> (forall a. c a => f a -> f' a) -> h f xs -> h f' xs Source #

Another name for `hcliftA`

.

*Since: 0.2*

hczipWith :: (AllN (Prod h) c xs, HAp h, HAp (Prod h)) => proxy c -> (forall a. c a => f a -> f' a -> f'' a) -> Prod h f xs -> h f' xs -> h f'' xs Source #

Another name for `hcliftA2`

.

*Since: 0.2*

hczipWith3 :: (AllN (Prod h) c xs, HAp h, HAp (Prod h)) => proxy c -> (forall a. c a => f a -> f' a -> f'' a -> f''' a) -> Prod h f xs -> Prod h f' xs -> h f'' xs -> h f''' xs Source #

Another name for `hcliftA3`

.

*Since: 0.2*

# Collapsing homogeneous structures

type family CollapseTo (h :: (k -> *) -> l -> *) (x :: *) :: * Source #

Maps products to lists, and sums to identities.

type CollapseTo [[k]] k (POP k) a Source # | |

type CollapseTo [[k]] k (SOP k) a Source # | |

type CollapseTo [k] k (NP k) a Source # | |

type CollapseTo [k] k (NS k) a Source # | |

class HCollapse h where Source #

A class for collapsing a heterogeneous structure into a homogeneous one.

hcollapse :: SListIN h xs => h (K a) xs -> CollapseTo h a Source #

Collapse a heterogeneous structure with homogeneous elements into a homogeneous structure.

If a heterogeneous structure is instantiated to the constant
functor `K`

, then it is in fact homogeneous. This function
maps such a value to a simpler Haskell datatype reflecting that.
An

contains a single `NS`

(`K`

a)`a`

, and an

contains
a list of `NP`

(`K`

a)`a`

s.

*Instances:*

`hcollapse`

,`collapse_NP`

::`NP`

(`K`

a) xs -> [a]`hcollapse`

,`collapse_NS`

::`NS`

(`K`

a) xs -> a`hcollapse`

,`collapse_POP`

::`POP`

(`K`

a) xss -> [[a]]`hcollapse`

,`collapse_SOP`

::`SOP`

(`K`

a) xss -> [a]

# Sequencing effects

class HAp h => HSequence h where Source #

A generalization of `sequenceA`

.

hsequence' :: (SListIN h xs, Applicative f) => h (f :.: g) xs -> f (h g xs) Source #

Corresponds to `sequenceA`

.

Lifts an applicative functor out of a structure.

*Instances:*

`hsequence'`

,`sequence'_NP`

:: (`SListI`

xs ,`Applicative`

f) =>`NP`

(f`:.:`

g) xs -> f (`NP`

g xs )`hsequence'`

,`sequence'_NS`

:: (`SListI`

xs ,`Applicative`

f) =>`NS`

(f`:.:`

g) xs -> f (`NS`

g xs )`hsequence'`

,`sequence'_POP`

:: (`SListI2`

xss,`Applicative`

f) =>`POP`

(f`:.:`

g) xss -> f (`POP`

g xss)`hsequence'`

,`sequence'_SOP`

:: (`SListI2`

xss,`Applicative`

f) =>`SOP`

(f`:.:`

g) xss -> f (`SOP`

g xss)

## Derived functions

hsequence :: (SListIN h xs, SListIN (Prod h) xs, HSequence h) => Applicative f => h f xs -> f (h I xs) Source #

Special case of `hsequence'`

where `g = `

.`I`

hsequenceK :: (SListIN h xs, SListIN (Prod h) xs, Applicative f, HSequence h) => h (K (f a)) xs -> f (h (K a) xs) Source #

Special case of `hsequence'`

where `g = `

.`K`

a

# Indexing into sums

A class for determining which choice in a sum-like structure a value represents.

hindex :: h f xs -> Int Source #

If `h`

is a sum-like structure representing a choice
between `n`

different options, and `x`

is a value of
type `h f xs`

, then

returns a number between
`hindex`

x`0`

and `n - 1`

representing the index of the choice
made by `x`

.

*Instances:*

`hindex`

,`index_NS`

::`NS`

f xs -> Int`hindex`

,`index_SOP`

::`SOP`

f xs -> Int

*Examples:*

`>>>`

2`hindex (S (S (Z (I False))))`

`>>>`

0`hindex (Z (K ()))`

`>>>`

1`hindex (SOP (S (Z (I True :* I 'x' :* Nil))))`

*Since: 0.2.4.0*

# Applying all injections

type family UnProd (h :: (k -> *) -> l -> *) :: (k -> *) -> l -> * Source #

Maps a structure containing products to the corresponding sum structure.

*Since: 0.2.4.0*

class UnProd (Prod h) ~ h => HApInjs h where Source #

A class for applying all injections corresponding to a sum-like structure to a table containing suitable arguments.

hapInjs :: SListIN h xs => Prod h f xs -> [h f xs] Source #

For a given table (product-like structure), produce a list where each element corresponds to the application of an injection function into the corresponding sum-like structure.

*Instances:*

`hapInjs`

,`apInjs_NP`

::`SListI`

xs =>`NP`

f xs -> [`NS`

f xs ]`hapInjs`

,`apInjs_SOP`

::`SListI2`

xss =>`POP`

f xs -> [`SOP`

f xss]

*Examples:*

`>>>`

[Z (I 'x'), S (Z (I True)), S (S (Z (I 2)))]`hapInjs (I 'x' :* I True :* I 2 :* Nil)`

`>>>`

[SOP (Z (I 'x' :* Nil)), SOP (S (Z (I True :* (I 2 :* Nil))))]`hapInjs (POP ((I 'x' :* Nil) :* (I True :* I 2 :* Nil) :* Nil)`

*Since: 0.2.4.0*

# Expanding sums to products

class HExpand h where Source #

A class for expanding sum structures into corresponding product structures, filling in the slots not targeted by the sum with default values.

*Since: 0.2.5.0*

hexpand :: SListIN (Prod h) xs => (forall x. f x) -> h f xs -> Prod h f xs Source #

Expand a given sum structure into a corresponding product structure by placing the value contained in the sum into the corresponding position in the product, and using the given default value for all other positions.

*Instances:*

`hexpand`

,`expand_NS`

::`SListI`

xs => (forall x . f x) ->`NS`

f xs ->`NP`

f xs`hexpand`

,`expand_SOP`

::`SListI2`

xss => (forall x . f x) ->`SOP`

f xss ->`POP`

f xss

*Examples:*

`>>>`

Nothing :* Just 3 :* Nothing :* Nil`hexpand Nothing (S (Z (Just 3))) :: NP Maybe '[Char, Int, Bool]`

`>>>`

POP (([] :* Nil) :* ([1,2] :* "xyz" :* Nil) :* Nil)`hexpand [] (SOP (S (Z ([1,2] :* "xyz" :* Nil)))) :: POP [] '[ '[Bool], '[Int, Char] ]`

*Since: 0.2.5.0*

hcexpand :: AllN (Prod h) c xs => proxy c -> (forall x. c x => f x) -> h f xs -> Prod h f xs Source #

Variant of `hexpand`

that allows passing a constrained default.

*Instances:*

`hcexpand`

,`cexpand_NS`

::`All`

c xs => proxy c -> (forall x . c x => f x) ->`NS`

f xs ->`NP`

f xs`hcexpand`

,`cexpand_SOP`

::`All2`

c xss => proxy c -> (forall x . c x => f x) ->`SOP`

f xss ->`POP`

f xss

*Examples:*

`>>>`

I False :* I 20 :* I LT :* Nil`hcexpand (Proxy :: Proxy Bounded) (I minBound) (S (Z (I 20))) :: NP I '[Bool, Int, Ordering]`

`>>>`

POP ((I 0.0 :* Nil) :* (I 1 :* I 2 :* Nil) :* Nil)`hcexpand (Proxy :: Proxy Num) (I 0) (SOP (S (Z (I 1 :* I 2 :* Nil)))) :: POP I '[ '[Double], '[Int, Int] ]`

*Since: 0.2.5.0*