witch 0.2.1.0 → 0.2.1.1
raw patch · 4 files changed
+108/−74 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- src/lib/Witch.hs +74/−47
- src/lib/Witch/TryCast.hs +3/−0
- src/lib/Witch/Utility.hs +30/−26
- witch.cabal +1/−1
src/lib/Witch.hs view
@@ -4,8 +4,63 @@ -- unqualified, so getting started is as easy as: -- -- >>> import Witch+--+-- In typical usage, you will most likely use 'Witch.Utility.into' for+-- 'Witch.Cast.Cast' instances and 'With.Utility.tryInto' for+-- 'Witch.TryCast.TryCast' instances. module Witch- ( -- * Motivation+ ( -- * Type classes++ -- ** Cast+ Witch.Cast.Cast(cast)+ , Witch.Utility.from+ , Witch.Utility.into++ -- ** TryCast+ , Witch.TryCast.TryCast(tryCast)+ , Witch.Utility.tryFrom+ , Witch.Utility.tryInto++ -- * Utilities+ , Witch.Utility.as+ , Witch.Utility.over+ , Witch.Utility.via+ , Witch.Utility.tryVia+ , Witch.Utility.maybeTryCast+ , Witch.Utility.eitherTryCast++ -- ** Unsafe+ -- | These functions should only be used in two circumstances: When you know+ -- a conversion is safe even though you can't prove it to the compiler, and+ -- when you're alright with your program crashing if the conversion fails.+ -- In all other cases you should prefer the normal conversion functions like+ -- 'Witch.Cast.cast'. And if you're converting a literal value, consider+ -- using the Template Haskell conversion functions like+ -- 'Witch.Lift.liftedCast'.+ , Witch.Utility.unsafeCast+ , Witch.Utility.unsafeFrom+ , Witch.Utility.unsafeInto++ -- ** Template Haskell+ -- | This library uses /typed/ Template Haskell, which may be a little+ -- different than what you're used to. Normally Template Haskell uses the+ -- @$(...)@ syntax for splicing in things to run at compile time. The typed+ -- variant uses the @$$(...)@ syntax for splices, doubling up on the dollar+ -- signs. Other than that, using typed Template Haskell should be pretty+ -- much the same as using regular Template Haskell.+ , Witch.Lift.liftedCast+ , Witch.Lift.liftedFrom+ , Witch.Lift.liftedInto++ -- * Data types+ , Witch.TryCastException.TryCastException(..)++ -- ** Casting+ , Witch.Casting.Casting(Casting)++ -- * Notes++ -- ** Motivation -- | Haskell provides many ways to convert between common types, and core -- libraries add even more. It can be challenging to know which function to -- use when converting from some source type @a@ to some target type @b@. It@@ -19,7 +74,7 @@ -- by the [@From@](https://doc.rust-lang.org/std/convert/trait.From.html) -- trait in Rust. - -- * Alternatives+ -- ** Alternatives -- | Many Haskell libraries already provide similar functionality. How is -- this library different? --@@ -67,7 +122,7 @@ -- if the conversion is possible, is it safe? For example converting a -- negative 'Int' into a 'Word' will overflow, which may be surprising. - -- * Instances+ -- ** Instances -- | When should you add a 'Witch.Cast.Cast' (or 'Witch.TryCast.TryCast') -- instance for some pair of types? This is a surprisingly tricky question -- to answer precisely. Instances are driven more by guidelines than rules.@@ -82,21 +137,33 @@ -- - Conversions should be lossless. If you have @Cast a b@ then no two @a@ -- values should be converted to the same @b@ value. --+ -- - Some conversions necessarily lose information, like converting from a+ -- list into a set.+ -- -- - If you have both @Cast a b@ and @Cast b a@, then -- @cast \@b \@a . cast \@a \@b@ should be the same as 'id'. In other -- words, @a@ and @b@ are isomorphic. --+ -- - This often true, but not always. For example, converting a list into+ -- a set will remove duplicates. And then converting back into a list+ -- will put the elements in ascending order.+ -- -- - If you have both @Cast a b@ and @Cast b c@, then you could also have -- @Cast a c@ and it should be the same as @cast \@b \@c . cast \@a \@b@. -- In other words, @Cast@ is transitive. --- -- In general if @s@ is a @t@, then you should add a 'Witch.Cast.Cast'- -- instance for it. But if @s@ merely can be a @t@, then you could add a+ -- - This is not always true. For example an @Int8@ may be represented as+ -- a number in JSON, whereas an @Int64@ might be represented as a+ -- string. That means @into \@JSON (into \@Int64 int8)@ would not be the+ -- same as @into \@JSON int8@.+ --+ -- In general if @s@ /is/ a @t@, then you should add a 'Witch.Cast.Cast'+ -- instance for it. But if @s@ merely /can be/ a @t@, then you could add a -- 'Witch.TryCast.TryCast' instance for it. And if it is technically -- possible to convert from @s@ to @t@ but there are a lot of caveats, you -- probably should not write any instances at all. - -- * Type applications+ -- ** Type applications -- | This library is designed to be used with the [@TypeApplications@](https://downloads.haskell.org/~ghc/9.0.1/docs/html/users_guide/exts/type_applications.html) -- language extension. Although it is not required for basic functionality, -- it is strongly encouraged. You can use 'Witch.Cast.cast',@@ -104,7 +171,7 @@ -- 'Witch.Lift.liftedCast' without type applications. Everything else -- requires a type application. - -- * Ambiguous types+ -- ** Ambiguous types -- | You may see @Identity@ show up in some type signatures. Anywhere you see -- @Identity a@, you can mentally replace it with @a@. It is a type family -- used to trick GHC into requiring type applications for certain functions.@@ -123,46 +190,6 @@ -- -- >>> from @Int8 1 :: Int16 -- 1-- -- * Type classes- -- ** Cast- Witch.Cast.Cast(cast)- , Witch.Utility.from- , Witch.Utility.into-- -- ** TryCast- , Witch.TryCast.TryCast(tryCast)- , Witch.Utility.tryFrom- , Witch.Utility.tryInto- , Witch.TryCastException.TryCastException(..)-- -- * Utilities- , Witch.Utility.as- , Witch.Utility.over- , Witch.Utility.via- , Witch.Utility.maybeTryCast- , Witch.Utility.eitherTryCast- , Witch.Utility.tryVia-- -- ** Unsafe- , Witch.Utility.unsafeCast- , Witch.Utility.unsafeFrom- , Witch.Utility.unsafeInto-- -- ** Template Haskell- -- | This library uses /typed/ Template Haskell, which may be a little- -- different than what you're used to. Normally Template Haskell uses the- -- @$(...)@ syntax for splicing in things to run at compile time. The typed- -- variant uses the @$$(...)@ syntax for splices, doubling up on the dollar- -- signs. Other than that, using typed Template Haskell should be pretty- -- much the same as using regular Template Haskell.- , Witch.Lift.liftedCast- , Witch.Lift.liftedFrom- , Witch.Lift.liftedInto-- -- * Data types- -- ** Casting- , Witch.Casting.Casting(Casting) ) where import qualified Witch.Cast
src/lib/Witch/TryCast.hs view
@@ -15,4 +15,7 @@ -- | This method implements the conversion of a value between types. At call -- sites you will usually want to use @tryFrom@ or @tryInto@ instead of this -- method.+ --+ -- Consider using @maybeTryCast@ or @eitherTryCast@ to implement this+ -- method. tryCast :: source -> Either (TryCastException.TryCastException source target) target
src/lib/Witch/Utility.hs view
@@ -60,7 +60,7 @@ -- that only works with one of them. -- -- > -- Avoid this:--- > from @t . f . from @s+-- > from @t . f . into @t -- > -- > -- Prefer this: -- > over @t f@@ -125,6 +125,35 @@ -> Either (TryCastException.TryCastException source target) target tryInto = TryCast.tryCast +-- | This is similar to 'via' except that it works with 'TryCast.TryCast'+-- instances instead. This function is especially convenient because juggling+-- the types in the 'TryCastException.TryCastException' can be tedious.+--+-- > -- Avoid this:+-- > case tryInto @u x of+-- > Left _ -> Left ...+-- > Right y -> case tryFrom @u y of+-- > Left _ -> Left ...+-- > Right z -> ...+-- >+-- > -- Prefer this:+-- > tryVia @u+tryVia+ :: forall u source target through+ . ( Identity.Identity u ~ through+ , TryCast.TryCast source through+ , TryCast.TryCast through target+ )+ => source+ -> Either (TryCastException.TryCastException source target) target+tryVia s = case TryCast.tryCast s of+ Left (TryCastException.TryCastException _ e) ->+ Left $ TryCastException.TryCastException s e+ Right u -> case TryCast.tryCast (u :: through) of+ Left (TryCastException.TryCastException _ e) ->+ Left $ TryCastException.TryCastException s e+ Right t -> Right t+ -- | This function can be used to implement 'TryCast.tryCast' with a function -- that returns 'Maybe'. For example: --@@ -162,31 +191,6 @@ Left e -> Left . TryCastException.TryCastException s . Just $ Exception.toException e Right t -> Right t---- | This is similar to 'via' except that it works with 'TryCast.TryCast'--- instances instead. This function is especially convenient because juggling--- the types in the 'TryCastException.TryCastException' can be tedious.------ > -- Avoid this:--- > fmap (tryFrom @u) . tryInto @u--- >--- > -- Prefer this:--- > tryVia @u-tryVia- :: forall u source target through- . ( Identity.Identity u ~ through- , TryCast.TryCast source through- , TryCast.TryCast through target- )- => source- -> Either (TryCastException.TryCastException source target) target-tryVia s = case TryCast.tryCast s of- Left (TryCastException.TryCastException _ e) ->- Left $ TryCastException.TryCastException s e- Right u -> case TryCast.tryCast (u :: through) of- Left (TryCastException.TryCastException _ e) ->- Left $ TryCastException.TryCastException s e- Right t -> Right t -- | This function is like 'TryCast.tryCast' except that it will throw an -- impure exception if the conversion fails.
witch.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: witch-version: 0.2.1.0+version: 0.2.1.1 synopsis: Convert values from one type into another. description: Witch converts values from one type into another.