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.
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.