Safe Haskell | Safe-Inferred |
---|---|
Language | GHC2021 |
Synopsis
- module Strongweak.Weaken
- module Strongweak.Strengthen
Instance design
A given strong type a
has exactly one associated weak type
.
Multiple strong types may weaken to the same weak type.Weaken
a
The following laws must hold:
weaken
a ==weaken
b |= a == bstrengthen
(weaken
a) ==pure
a
strongweak is largely a programmer convenience library. There is a lot of room to write instances which may seem useful on first glance, but are inconsistent with the overall design. Here is some relevant guidance.
- Weak types should have _simpler invariants to manage_ than strong ones.
- In general, weak types should be easier to use than strong ones.
- Most (all?) instances should handle (relax or assert) a single invariant.
- Most instances should not have a recursive context.
Some types may not have any invariants which may be usefully relaxed e.g.
. For these, you may write a recursive instance that
weakens/strengthens "through" the type e.g. Either
a b(
). Don't combine the two instance types.Weaken
a, Weaken
b) => Weak
(Either
a b)
An example is
. We could weaken this to NonEmpty
a[a]
,
but also to [
. However, the latter would mean decomposing and
removing an invariant simultaneously. It would be two separate strengthens in
one instance. And now, your Weaken
a]a
must be in the strongweak ecosystem, which isn't
necessarily what you want - indeed, it appears this sort of design would require
a
overlapping instance, which I do not want. On the
other hand, Weaken
a = a, weaken = id[a]
does weaken to [
, because there are no invariants
present to remove, so decomposing is all the user could hope to do.Weaken
a]
Re-exports
module Strongweak.Weaken
module Strongweak.Strengthen