Skip to content

Commit

Permalink
amend various haddocks
Browse files Browse the repository at this point in the history
  • Loading branch information
raehik committed Feb 22, 2023
1 parent b8e982f commit 44c3d3d
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 33 deletions.
8 changes: 8 additions & 0 deletions src/Strongweak.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ import Strongweak.Strengthen

{- $strongweak-instance-design
A given strong type @a@ has exactly one associated weak type @'Weak' a@.
Multiple strong types may weaken to the same weak type.
The following laws must hold:
* @'weaken' a == 'weaken' b |= a == b@
* @'strengthen' ('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.
Expand Down
16 changes: 6 additions & 10 deletions src/Strongweak/Strengthen.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,19 @@ import Data.Functor.Const
import Data.List.NonEmpty ( NonEmpty( (:|) ) )
import Data.List.NonEmpty qualified as NonEmpty

{- | You may attempt to transform a @'Weak' a@ to an @a@.
Laws:
* @a === b -> 'strengthen' a === 'strengthen' b@
* @'strengthen' ('weaken' a) === 'Success' a@
{- | Attempt to strengthen some @'Weak' a@, asserting certain invariants.
We take 'Weaken' as a superclass in order to maintain strong/weak type pair
consistency. We choose this dependency direction because we treat the strong
type as the "canonical" one, so 'Weaken' is the more natural (and
straightforward) class to define.
straightforward) class to define. That does mean the instances for this class
are a little confusingly worded. Alas.
Instances should /either/ handle an invariant, or decompose. See "Strongweak"
for a discussion on this design.
See "Strongweak" for class design notes and laws.
-}
class Weaken a => Strengthen a where
-- | Attempt to transform a weak value to its associated strong one.
-- | Attempt to strengthen some @'Weak' a@ to its associated strong type
-- @a@.
strengthen :: Weak a -> Validation (NonEmpty StrengthenFail) a

-- | Weaken a strong value, then strengthen it again.
Expand Down
14 changes: 6 additions & 8 deletions src/Strongweak/Strengthen/Unsafe.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import Data.List.NonEmpty ( NonEmpty )

{- | Unsafely transform a @'Weak' a@ to an @a@, without asserting invariants.
Naturally, you must only even /consider/ using this if you have a guarantee that
your value is safe to treat as strong.
For example, you may unsafely strengthen some @'Numeric.Natural.Natural' n@ into
a 'Word8' by unsafely coercing the value, ignoring the possibility that @n >=
255@.
Expand All @@ -24,17 +27,12 @@ doesn't fit in its strong counterpart? That depends on the strengthen.
* Numeric coercions should safely overflow.
* Some will raise an error (e.g. 'NonEmpty').
* Others will appear to work, but later explode your computer (sized vectors
will probably do this).
Only consider using this if you have a guarantee that your value is safe to
treat as strong.
* Others will appear to work, but later explode your computer.
Instances should /either/ handle an invariant, or decompose. See "Strongweak"
for a discussion on this design.
See "Strongweak" for class design notes and laws.
-}
class Weaken a => UnsafeStrengthen a where
-- | Unsafely transform a weak value to its associated strong one.
-- | Unsafely transform a @'Weak' a@ to its associated strong type @a@.
unsafeStrengthen :: Weak a -> a

-- | Add a refinement to a type without checking the associated predicate.
Expand Down
19 changes: 4 additions & 15 deletions src/Strongweak/Weaken.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,15 @@ import Data.Functor.Const
import Data.List.NonEmpty qualified as NonEmpty
import Data.List.NonEmpty ( NonEmpty )

{- | Transform an @a@ to a @'Weak' a@.
{- | Weaken some @a@, relaxing certain invariants.
A given strong type @a@ has exactly one associated weak type @'Weak' a@.
Multiple strong types may weaken to the same weak type.
The following laws must hold:
* @a == b |= 'weaken' a == 'weaken' b@
* round-trip: @'strengthen' ('weaken' a) == 'pure' a@
Most instances should strip an invariant, and not have a recursive context. Some
types don't have an invariant
/either/ handle an invariant, or decompose. See "Strongweak"
for a discussion on this design.
See "Strongweak" for class design notes and laws.
-}
class Weaken a where
-- | The type to weaken to.
-- | The weakened type for some type.
type Weak a :: Type

-- | Transform a strong value to its associated weak one.
-- | Weaken some @a@ to its associated weak type @'Weak' a@.
weaken :: a -> Weak a

-- | Lift a function on a weak type to the associated strong type.
Expand Down

0 comments on commit 44c3d3d

Please sign in to comment.