Copyright | (C) Koz Ross 2019 |
---|---|

License | GPL version 3.0 or later |

Stability | Experimental |

Portability | GHC only |

Safe Haskell | None |

Language | Haskell2010 |

This allows us to 'borrow' implementations of certain type classes from
'larger' finitary types for 'smaller' finitary types. Essentially, for
any types `a`

and `b`

, if both `a`

and `b`

are `Finitary`

and ```
Cardinality a
<= Cardinality b
```

, the set of indexes for `a`

is a subset (strictly speaking,
a prefix) of the set of indexes for `b`

. Therefore, we have an injective
mapping from `a`

to `b`

, whose
preimage
is also injective, witnessed by the function `fromFinite . toFinite`

in both
directions. When combined with the monotonicity of `toFinite`

and
`fromFinite`

, we can operate on inhabitants of `b`

in certain ways while
always being able to recover the 'equivalent' inhabitant of `a`

.

On this basis, we can 'borrow' both `Unbox`

and `Storable`

instances
from `b`

. This is done by way of the `PackInto a b`

type; here, `a`

is the
type to which instances are being 'lent' and `b`

is the type from which
instances are being 'borrowed'. `PackInto a b`

does not store any values of
type `a`

- construction and deconstruction of `PackInto`

performs a
conversion as described above.

If an existing `Finitary`

type exists with desired instances, this encoding
is the most flexible and efficient. Unless you have good reasons to consider
something else (such as space use), use this encoding. However, its
usefulness is conditional on a suitable 'packing' type existing of
appropriate cardinality. Additionally, if `Cardinality a < Cardinality b`

,
any `PackInto a b`

will waste some space, with larger cardinality differences
creating proportionately more waste.

## Synopsis

- data PackInto (a :: Type) (b :: Type)
- pattern Packed :: forall (b :: Type) (a :: Type). (Finitary a, Finitary b, Cardinality a <= Cardinality b) => a -> PackInto a b

# Documentation

data PackInto (a :: Type) (b :: Type) Source #

An opaque wrapper, representing values of type `a`

as 'corresponding'
values of type `b`

.

#### Instances

pattern Packed :: forall (b :: Type) (a :: Type). (Finitary a, Finitary b, Cardinality a <= Cardinality b) => a -> PackInto a b Source #

To provide (something that resembles a) data constructor for `PackInto`

, we
provide the following pattern. It can be used like any other data
constructor:

import Data.Finitary.PackInt anInt :: PackInto Int Word anInt = Packed 10 isPackedEven :: PackInto Int Word -> Bool isPackedEven (Packed x) = even x

**Every** pattern match, and data constructor call, performs a re-encoding by
way of `fromFinite . toFinite`

on `b`

and `a`

respectively. Use with this in
mind.