packages feed

witch 0.0.0.2 → 0.0.0.3

raw patch · 3 files changed

+145/−119 lines, 3 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Witch: class From a b
- Witch: instance GHC.Classes.Ord a => Witch.From [a] (Data.Set.Internal.Set a)
- Witch: instance GHC.Classes.Ord k => Witch.From [(k, v)] (Data.Map.Internal.Map k v)
- Witch: instance Witch.From (Data.Map.Internal.Map k v) [(k, v)]
- Witch: instance Witch.From (Data.Sequence.Internal.Seq a) [a]
- Witch: instance Witch.From (Data.Set.Internal.Set a) [a]
- Witch: instance Witch.From (GHC.Base.NonEmpty a) [a]
- Witch: instance Witch.From (a, b) (b, a)
- Witch: instance Witch.From (a, x) a
- Witch: instance Witch.From (x, a) a
- Witch: instance Witch.From Data.ByteString.Internal.ByteString Data.ByteString.Lazy.Internal.ByteString
- Witch: instance Witch.From Data.ByteString.Internal.ByteString [GHC.Word.Word8]
- Witch: instance Witch.From Data.ByteString.Lazy.Internal.ByteString Data.ByteString.Internal.ByteString
- Witch: instance Witch.From Data.Text.Internal.Lazy.Text Data.Text.Internal.Text
- Witch: instance Witch.From Data.Text.Internal.Text Data.Text.Internal.Lazy.Text
- Witch: instance Witch.From Data.Text.Internal.Text GHC.Base.String
- Witch: instance Witch.From Data.Void.Void x
- Witch: instance Witch.From GHC.Base.String Data.Text.Internal.Text
- Witch: instance Witch.From GHC.Int.Int16 GHC.Int.Int32
- Witch: instance Witch.From GHC.Int.Int32 GHC.Int.Int64
- Witch: instance Witch.From GHC.Int.Int8 GHC.Int.Int16
- Witch: instance Witch.From GHC.Integer.Type.Integer GHC.Real.Rational
- Witch: instance Witch.From GHC.Natural.Natural GHC.Integer.Type.Integer
- Witch: instance Witch.From GHC.Types.Bool GHC.Types.Int
- Witch: instance Witch.From GHC.Types.Char GHC.Types.Int
- Witch: instance Witch.From GHC.Types.Float GHC.Types.Double
- Witch: instance Witch.From GHC.Types.Int GHC.Integer.Type.Integer
- Witch: instance Witch.From GHC.Types.Word GHC.Natural.Natural
- Witch: instance Witch.From GHC.Word.Word16 GHC.Word.Word32
- Witch: instance Witch.From GHC.Word.Word32 GHC.Word.Word64
- Witch: instance Witch.From GHC.Word.Word8 GHC.Word.Word16
- Witch: instance Witch.From [GHC.Word.Word8] Data.ByteString.Internal.ByteString
- Witch: instance Witch.From [a] (Data.Sequence.Internal.Seq a)
- Witch: instance Witch.From a (Data.Either.Either a x)
- Witch: instance Witch.From a (Data.Either.Either x a)
- Witch: instance Witch.From a (GHC.Maybe.Maybe a)
- Witch: instance Witch.From a (x -> a)
- Witch: instance Witch.From a [a]
- Witch: instance Witch.From a a
+ Witch: cast :: (Cast source target, Coercible source target) => source -> target
+ Witch: class Cast source target
+ Witch: instance GHC.Classes.Ord a => Witch.Cast [a] (Data.Set.Internal.Set a)
+ Witch: instance GHC.Classes.Ord k => Witch.Cast [(k, v)] (Data.Map.Internal.Map k v)
+ Witch: instance Witch.Cast (Data.Map.Internal.Map k v) [(k, v)]
+ Witch: instance Witch.Cast (Data.Sequence.Internal.Seq a) [a]
+ Witch: instance Witch.Cast (Data.Set.Internal.Set a) [a]
+ Witch: instance Witch.Cast (GHC.Base.NonEmpty a) [a]
+ Witch: instance Witch.Cast (a, b) (b, a)
+ Witch: instance Witch.Cast (a, x) a
+ Witch: instance Witch.Cast (x, a) a
+ Witch: instance Witch.Cast Data.ByteString.Internal.ByteString Data.ByteString.Lazy.Internal.ByteString
+ Witch: instance Witch.Cast Data.ByteString.Internal.ByteString [GHC.Word.Word8]
+ Witch: instance Witch.Cast Data.ByteString.Lazy.Internal.ByteString Data.ByteString.Internal.ByteString
+ Witch: instance Witch.Cast Data.Text.Internal.Lazy.Text Data.Text.Internal.Text
+ Witch: instance Witch.Cast Data.Text.Internal.Text Data.Text.Internal.Lazy.Text
+ Witch: instance Witch.Cast Data.Text.Internal.Text GHC.Base.String
+ Witch: instance Witch.Cast Data.Void.Void x
+ Witch: instance Witch.Cast GHC.Base.String Data.Text.Internal.Text
+ Witch: instance Witch.Cast GHC.Int.Int16 GHC.Int.Int32
+ Witch: instance Witch.Cast GHC.Int.Int32 GHC.Int.Int64
+ Witch: instance Witch.Cast GHC.Int.Int8 GHC.Int.Int16
+ Witch: instance Witch.Cast GHC.Integer.Type.Integer GHC.Real.Rational
+ Witch: instance Witch.Cast GHC.Natural.Natural GHC.Integer.Type.Integer
+ Witch: instance Witch.Cast GHC.Types.Bool GHC.Types.Int
+ Witch: instance Witch.Cast GHC.Types.Char GHC.Types.Int
+ Witch: instance Witch.Cast GHC.Types.Float GHC.Types.Double
+ Witch: instance Witch.Cast GHC.Types.Int GHC.Integer.Type.Integer
+ Witch: instance Witch.Cast GHC.Types.Word GHC.Natural.Natural
+ Witch: instance Witch.Cast GHC.Word.Word16 GHC.Word.Word32
+ Witch: instance Witch.Cast GHC.Word.Word32 GHC.Word.Word64
+ Witch: instance Witch.Cast GHC.Word.Word8 GHC.Word.Word16
+ Witch: instance Witch.Cast [GHC.Word.Word8] Data.ByteString.Internal.ByteString
+ Witch: instance Witch.Cast [a] (Data.Sequence.Internal.Seq a)
+ Witch: instance Witch.Cast a (Data.Either.Either a x)
+ Witch: instance Witch.Cast a (Data.Either.Either x a)
+ Witch: instance Witch.Cast a (GHC.Maybe.Maybe a)
+ Witch: instance Witch.Cast a (x -> a)
+ Witch: instance Witch.Cast a [a]
+ Witch: instance Witch.Cast a a
- Witch: from :: (From a b, Coercible a b) => a -> b
+ Witch: from :: forall s target source. (Ambiguous s ~ source, Cast source target) => source -> target
- Witch: into :: forall b a. From a b => a -> b
+ Witch: into :: forall t source target. (Ambiguous t ~ target, Cast source target) => source -> target
- Witch: via :: forall b a c. (From a b, From b c) => a -> c
+ Witch: via :: forall through source target. (Cast source through, Cast through target) => source -> target

Files

README.markdown view
@@ -1,3 +1,7 @@ # Witch +[![CI](https://github.com/tfausak/witch/workflows/CI/badge.svg)](https://github.com/tfausak/witch/actions)+[![Hackage](https://img.shields.io/hackage/v/witch)](https://hackage.haskell.org/package/witch)+[![Stackage](https://www.stackage.org/package/witch/badge/nightly?label=stackage)](https://www.stackage.org/package/witch)+ :mage_woman: Convert values from one type into another.
src/lib/Witch.hs view
@@ -3,8 +3,9 @@ {-# language FlexibleInstances #-} {-# language MultiParamTypeClasses #-} {-# language ScopedTypeVariables #-}+{-# language TypeFamilies #-} --- | This module provides the 'From' type class for converting values between+-- | This module provides the 'Cast' type class for converting values between -- various types. This aims to be a common interface for the various @xToY@ or -- @yFromX@ functions you might write instead. It is inspired by the -- @std::convert::From@ trait that the Rust programming language provides.@@ -35,7 +36,7 @@ -- - <https://github.com/kframework/kore/blob/626f230/kore/src/From.hs>: --   This package is not available on Hackage, but otherwise is very similar to --   this one.-module Witch (From(from), into, via) where+module Witch (Cast(cast), from, into, via) where  import qualified Data.ByteString as ByteString import qualified Data.ByteString.Lazy as LazyByteString@@ -54,7 +55,7 @@ import qualified Numeric.Natural as Natural  -- | This type class represents a way to convert values from some type into--- another type. The constraint @From a b@ means that you can convert from a+-- another type. The constraint @Cast a b@ means that you can convert from a -- value of type @a@ into a value of type @b@. -- -- This is primarily intended for "zero cost" conversions like @newtype@s. For@@ -62,8 +63,8 @@ -- say: -- -- > newtype Name = Name String--- > instance From String Name--- > instance From Name String+-- > instance Cast String Name+-- > instance Cast Name String -- -- And then you could convert back and forth between @Name@s and @String@s: --@@ -75,8 +76,8 @@ -- This type class does not have any laws, but it does have some expectations: -- -- - Conversions should be total. A conversion should never fail or crash.---   Avoid writing instances like @From Int (Maybe Char)@. (It might be---   worthwhile to have a separate @TryFrom@ type class for this.)+--   Avoid writing instances like @Cast Int (Maybe Char)@. (It might be+--   worthwhile to have a separate @TryCast@ type class for this.) -- -- - Conversions should be unambiguous. For example there are many ways to --   decode a @ByteString@ into @Text@, so you shouldn't provide an instance@@ -86,213 +87,233 @@ --   @String@ to @Text@ is probably fine, but converting from a UTF-8 encoded --   @ByteString@ to @Text@ is problematic. ----- - Conversions should be lossless. In other words if you have @From a b@ then+-- - Conversions should be lossless. In other words if you have @Cast a b@ then --   no two @a@ values should be converted to the same @b@ value. For example---   @From Int Integer@ is fine because every @Int@ can be mapped to a---   corresponding @Integer@, but @From Integer Int@ is not good because some+--   @Cast Int Integer@ is fine because every @Int@ can be mapped to a+--   corresponding @Integer@, but @Cast Integer Int@ is not good because some --   @Integer@s are out of bounds and would need to be clamped. ----- - If you have both @From a b@ and @From b a@, then @from . from@ should be+-- - If you have both @Cast a b@ and @Cast b a@, then @cast . cast@ should be --   the same as 'id'. In other words @a@ and @b@ are isomorphic. ----- - If you have both @From a b@ and @From b c@, then it's up to you if you---   want to provide @From a c@. Sometimes using 'via' is ergonomic enough,+-- - If you have both @Cast a b@ and @Cast b c@, then it's up to you if you+--   want to provide @Cast a c@. Sometimes using 'via' is ergonomic enough, --   other times you want the extra instance. (It would be nice if we could---   provide @instance (From a b, From b c) => From a c where from = via \@b@.)-class From a b where-  -- | This method converts a value from one type into another. This is-  -- intended to be used with the @TypeApplications@ language extension. For-  -- example, here are a few ways to convert from an 'Int' into an 'Integer':-  ---  -- > from @Int @Integer 123-  -- > from @_ @Integer (123 :: Int)-  -- > from @Int @_ 123 :: Integer-  -- > from @Int 123 :: Integer-  -- > from (123 :: Int) :: Integer-  ---  -- Often the context around an expression will make the explicit type-  -- signatures unnecessary. If you find yourself using a partial type-  -- signature, consider using 'into' instead. For example:-  ---  -- > let someInt = 123 :: Int-  -- > from @_ @Integer someInt -- avoid this-  -- > into @Integer someInt -- prefer this+--   provide @instance (Cast a b, Cast b c) => Cast a c where cast = via \@b@.)+class Cast source target where+  -- | This method implements the conversion of a value between types. In+  -- practice most instances don't need an explicit implementation. At call+  -- sites you'll usually want to use 'from' or 'into' instead of 'cast'.   ---  -- The default implementation of 'from' simply calls 'Coerce.coerce', which+  -- The default implementation of 'cast' simply calls 'Coerce.coerce', which   -- works for types that have the same runtime representation.-  from :: a -> b-  default from :: Coerce.Coercible a b => a -> b-  from = Coerce.coerce+  cast :: source -> target+  default cast :: Coerce.Coercible source target => source -> target+  cast = Coerce.coerce +-- This ugly hack is used to require type applications when calling 'from' and+-- 'into'. See <https://twitter.com/taylorfausak/status/1329084033003782148>.+data Never+type family Ambiguous a where+  Ambiguous Never = ()+  Ambiguous a = a++-- | This function converts a value from one type into another. This is+-- intended to be used with the @TypeApplications@ language extension. The+-- @Ambiguous@ type in the signature makes a type application required. If+-- you'd prefer not to provide a type application, use 'cast' instead.+--+-- As an example, here are a few ways to convert from an 'Int' into an+-- 'Integer':+--+-- > from @Int @Integer 123+-- > from @_ @Integer (123 :: Int)+-- > from @Int @_ 123 :: Integer+-- > from @Int 123 :: Integer+--+-- Often the context around an expression will make the explicit type+-- signatures unnecessary. If you find yourself using a partial type+-- signature, consider using 'into' instead. For example:+--+-- > let someInt = 123 :: Int+-- > from @_ @Integer someInt -- avoid this+-- > into @Integer someInt -- prefer this+--+from :: forall s target source . (Ambiguous s ~ source, Cast source target) => source -> target+from = cast+ -- | This function converts a value from one type into another. This is the -- same as 'from' except that the type variables are in the opposite order.-into :: forall b a . From a b => a -> b-into = from+into :: forall t source target . (Ambiguous t ~ target, Cast source target) => source -> target+into = cast  -- | This function converts a value from one type into another by going through--- some third type. This is the same as calling 'from' (or 'into') twice, but--- can sometimes be more convenient.+-- some third type. This is the same as calling 'cast' (or 'from' or 'into')+-- twice, but can sometimes be more convenient. -- -- Note that the type in the middle of the conversion is the first type -- variable of this function. In other words, @via \@b \@a \@c@ first converts -- from @a@ to @b@, and then from @b@ to @c@. Often both @a@ and @c@ will be -- inferred from context, which means you can just write @via \@b@.-via :: forall b a c . (From a b, From b c) => a -> c-via = from . (\ x -> x :: b) . from+via :: forall through source target . (Cast source through, Cast through target) => source -> target+via = cast . (\ x -> x :: through) . cast  -- | 'id'-instance From a a where-  from = id+instance Cast a a where+  cast = id  -- | 'const'-instance From a (x -> a) where-  from = const+instance Cast a (x -> a) where+  cast = const  -- | 'pure'-instance From a [a] where-  from = pure+instance Cast a [a] where+  cast = pure  -- | 'Just'-instance From a (Maybe a) where-  from = Just+instance Cast a (Maybe a) where+  cast = Just  -- | 'Left'-instance From a (Either a x) where-  from = Left+instance Cast a (Either a x) where+  cast = Left  -- | 'Right'-instance From a (Either x a) where-  from = Right+instance Cast a (Either x a) where+  cast = Right  -- | 'Void.absurd'-instance From Void.Void x where-  from = Void.absurd+instance Cast Void.Void x where+  cast = Void.absurd  -- | 'fst'-instance From (a, x) a where-  from = fst+instance Cast (a, x) a where+  cast = fst  -- | 'snd'-instance From (x, a) a where-  from = snd+instance Cast (x, a) a where+  cast = snd  -- | 'Tuple.swap'-instance From (a, b) (b, a) where-  from = Tuple.swap+instance Cast (a, b) (b, a) where+  cast = Tuple.swap  -- | 'NonEmpty.toList'-instance From (NonEmpty.NonEmpty a) [a] where-  from = NonEmpty.toList+instance Cast (NonEmpty.NonEmpty a) [a] where+  cast = NonEmpty.toList  -- | 'fromIntegral'-instance From Word.Word8 Word.Word16 where-  from = fromIntegral+instance Cast Word.Word8 Word.Word16 where+  cast = fromIntegral  -- | 'fromIntegral'-instance From Word.Word16 Word.Word32 where-  from = fromIntegral+instance Cast Word.Word16 Word.Word32 where+  cast = fromIntegral  -- | 'fromIntegral'-instance From Word.Word32 Word.Word64 where-  from = fromIntegral+instance Cast Word.Word32 Word.Word64 where+  cast = fromIntegral  -- | 'fromIntegral'-instance From Word Natural.Natural where-  from = fromIntegral+instance Cast Word Natural.Natural where+  cast = fromIntegral  -- | 'fromIntegral'-instance From Natural.Natural Integer where-  from = fromIntegral+instance Cast Natural.Natural Integer where+  cast = fromIntegral  -- | 'fromIntegral'-instance From Int.Int8 Int.Int16 where-  from = fromIntegral+instance Cast Int.Int8 Int.Int16 where+  cast = fromIntegral  -- | 'fromIntegral'-instance From Int.Int16 Int.Int32 where-  from = fromIntegral+instance Cast Int.Int16 Int.Int32 where+  cast = fromIntegral  -- | 'fromIntegral'-instance From Int.Int32 Int.Int64 where-  from = fromIntegral+instance Cast Int.Int32 Int.Int64 where+  cast = fromIntegral  -- | 'fromIntegral'-instance From Int Integer where-  from = fromIntegral+instance Cast Int Integer where+  cast = fromIntegral  -- | 'fromIntegral'-instance From Integer Rational where-  from = fromIntegral+instance Cast Integer Rational where+  cast = fromIntegral  -- | 'realToFrac'-instance From Float Double where-  from = realToFrac+instance Cast Float Double where+  cast = realToFrac  -- | 'fromEnum'-instance From Bool Int where-  from = fromEnum+instance Cast Bool Int where+  cast = fromEnum  -- | 'fromEnum'-instance From Char Int where-  from = fromEnum+instance Cast Char Int where+  cast = fromEnum  -- | 'ByteString.pack'-instance From [Word.Word8] ByteString.ByteString where-  from = ByteString.pack+instance Cast [Word.Word8] ByteString.ByteString where+  cast = ByteString.pack  -- | 'ByteString.unpack'-instance From ByteString.ByteString [Word.Word8] where-  from = ByteString.unpack+instance Cast ByteString.ByteString [Word.Word8] where+  cast = ByteString.unpack  -- | 'LazyByteString.fromStrict'-instance From ByteString.ByteString LazyByteString.ByteString where-  from = LazyByteString.fromStrict+instance Cast ByteString.ByteString LazyByteString.ByteString where+  cast = LazyByteString.fromStrict  -- | 'LazyByteString.toStrict'-instance From LazyByteString.ByteString ByteString.ByteString where-  from = LazyByteString.toStrict+instance Cast LazyByteString.ByteString ByteString.ByteString where+  cast = LazyByteString.toStrict  -- | 'Text.pack'-instance From String Text.Text where-  from = Text.pack+--+-- Note that some 'Char' values cannot be represented in 'Text' and will be+-- replaced by U+FFFD.+instance Cast String Text.Text where+  cast = Text.pack  -- | 'Text.unpack'-instance From Text.Text String where-  from = Text.unpack+instance Cast Text.Text String where+  cast = Text.unpack  -- | 'LazyText.fromStrict'-instance From Text.Text LazyText.Text where-  from = LazyText.fromStrict+instance Cast Text.Text LazyText.Text where+  cast = LazyText.fromStrict  -- | 'LazyText.toStrict'-instance From LazyText.Text Text.Text where-  from = LazyText.toStrict+instance Cast LazyText.Text Text.Text where+  cast = LazyText.toStrict  -- | 'Seq.fromList'-instance From [a] (Seq.Seq a) where-  from = Seq.fromList+instance Cast [a] (Seq.Seq a) where+  cast = Seq.fromList  -- | 'Foldable.toList'-instance From (Seq.Seq a) [a] where-  from = Foldable.toList+instance Cast (Seq.Seq a) [a] where+  cast = Foldable.toList  -- | 'Set.fromList' -- -- Note that this will remove duplicate elements from the list.-instance Ord a => From [a] (Set.Set a) where-  from = Set.fromList+instance Ord a => Cast [a] (Set.Set a) where+  cast = Set.fromList  -- | 'Set.toAscList'-instance From (Set.Set a) [a] where-  from = Set.toAscList+instance Cast (Set.Set a) [a] where+  cast = Set.toAscList  -- | 'Map.fromList' -- -- Note that if there are duplicate keys in the list, the one closest to the -- end will win.-instance Ord k => From [(k, v)] (Map.Map k v) where-  from = Map.fromList+instance Ord k => Cast [(k, v)] (Map.Map k v) where+  cast = Map.fromList  -- | 'Map.toAscList'-instance From (Map.Map k v) [(k, v)] where-  from = Map.toAscList+instance Cast (Map.Map k v) [(k, v)] where+  cast = Map.toAscList
witch.cabal view
@@ -9,7 +9,7 @@ maintainer: Taylor Fausak name: witch synopsis: Convert values from one type into another.-version: 0.0.0.2+version: 0.0.0.3  source-repository head   location: https://github.com/tfausak/witch@@ -26,6 +26,7 @@   ghc-options:     -Weverything     -Wno-implicit-prelude+    -Wno-redundant-constraints     -Wno-safe     -Wno-unsafe   hs-source-dirs: src/lib