packages feed

strongweak 0.4.0 → 0.4.1

raw patch · 8 files changed

+81/−34 lines, 8 files

Files

CHANGELOG.md view
@@ -1,3 +1,6 @@+## 0.4.1 (2023-02-22)+  * add `DerivingVia` wrapper for generic instances (like `Generically`)+ ## 0.4.0 (2023-02-22)   * redesign some instances to avoid the decomposer style     * alter `Identity`, `Const` instances
src/Strongweak.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE UndecidableInstances #-} module Strongweak   (   -- * Instance design@@ -12,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
src/Strongweak/Generic.hs view
@@ -8,10 +8,14 @@   -- * Generic derivers     weakenGeneric   , strengthenGeneric++  -- * Generic wrapper+  , GenericallySW(..)   ) where  import Strongweak.Generic.Weaken import Strongweak.Generic.Strengthen+import Strongweak.Generic.Via  {- $generic-derivation-compatibility 
+ src/Strongweak/Generic/Via.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE UndecidableInstances #-} -- required due to nested constraints++module Strongweak.Generic.Via where++import Strongweak.Generic.Weaken+import Strongweak.Generic.Strengthen+import Strongweak+import GHC.Generics+import Data.Kind++{- | @DerivingVia@ wrapper for strongweak instances.++We can't use 'Generically' conveniently because we need to talk about two data+types, not one -- we would have to do something like @'Generically' ('Tagged' w+s)@, which is ugly. So we instead define our own adorable little "via type"+here!++Use like so:++@+data XYZ (s :: Strength) = XYZ+  { xyz1 :: SW s Word8+  , xyz2 :: Word8+  , xyz3 :: ()+  } deriving stock Generic+deriving via (GenericallySW (XYZ 'Strong) (XYZ 'Weak)) instance Weaken (XYZ 'Strong)+deriving via (GenericallySW (XYZ 'Strong) (XYZ 'Weak)) instance Strengthen (XYZ 'Strong)+@++TODO can't figure out a way around multiple standalone deriving declarations :(+-}++newtype GenericallySW s (w :: Type) = GenericallySW { unGenericallySW :: s }++instance+  ( Generic s, Generic w+  , GWeaken (Rep s) (Rep w)+  ) => Weaken (GenericallySW s w) where+    type Weak (GenericallySW s w) = w+    weaken = weakenGeneric . unGenericallySW++instance+  ( Generic s, Generic w+  , GStrengthenD (Rep w) (Rep s)+  , Weaken (GenericallySW s w)+  ) => Strengthen (GenericallySW s w) where+    strengthen = fmap GenericallySW . strengthenGeneric
src/Strongweak/Strengthen.hs view
@@ -40,23 +40,19 @@ 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.
src/Strongweak/Strengthen/Unsafe.hs view
@@ -15,6 +15,9 @@  {- | 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@.@@ -24,17 +27,12 @@    * 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.
src/Strongweak/Weaken.hs view
@@ -21,26 +21,15 @@ import Data.List.NonEmpty qualified as NonEmpty import Data.List.NonEmpty ( NonEmpty ) -{- | Transform an @a@ to a @'Weak' a@.--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@+{- | Weaken some @a@, relaxing certain invariants. -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.
strongweak.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           strongweak-version:        0.4.0+version:        0.4.1 synopsis:       Convert between strong and weak representations of types description:    Please see README.md. category:       Data@@ -31,6 +31,7 @@       Strongweak       Strongweak.Generic       Strongweak.Generic.Strengthen+      Strongweak.Generic.Via       Strongweak.Generic.Weaken       Strongweak.Strengthen       Strongweak.Strengthen.Unsafe