lawful-conversions 0.1.7 → 0.4.0
raw patch · 75 files changed
Files
- CHANGELOG.md +19/−0
- lawful-conversions.cabal +8/−27
- src/library/LawfulConversions.hs +7/−10
- src/library/LawfulConversions/Algebra.hs +225/−0
- src/library/LawfulConversions/Classes.hs +0/−158
- src/library/LawfulConversions/Optics.hs +2/−2
- src/library/LawfulConversions/Prelude.hs +0/−1
- src/library/LawfulConversions/Properties.hs +41/−16
- src/library/LawfulConversions/Proxies/ViaIsSome.hs +1/−1
- src/library/LawfulConversions/Relations.hs +2/−21
- src/library/LawfulConversions/Relations/Any.hs +17/−0
- src/library/LawfulConversions/Relations/BoxedVectorAndList.hs +1/−1
- src/library/LawfulConversions/Relations/BoxedVectorAndSeq.hs +1/−1
- src/library/LawfulConversions/Relations/ByteArrayAndByteString.hs +1/−1
- src/library/LawfulConversions/Relations/ByteArrayAndLazyByteString.hs +1/−1
- src/library/LawfulConversions/Relations/ByteArrayAndLazyByteStringBuilder.hs +1/−1
- src/library/LawfulConversions/Relations/ByteArrayAndShortByteString.hs +1/−1
- src/library/LawfulConversions/Relations/ByteArrayAndTextArray.hs +1/−1
- src/library/LawfulConversions/Relations/ByteArrayAndWord8List.hs +1/−1
- src/library/LawfulConversions/Relations/ByteStringAndLazyByteString.hs +1/−1
- src/library/LawfulConversions/Relations/ByteStringAndLazyByteStringBuilder.hs +1/−1
- src/library/LawfulConversions/Relations/ByteStringAndLazyText.hs +0/−19
- src/library/LawfulConversions/Relations/ByteStringAndShortByteString.hs +1/−1
- src/library/LawfulConversions/Relations/ByteStringAndString.hs +0/−18
- src/library/LawfulConversions/Relations/ByteStringAndText.hs +0/−17
- src/library/LawfulConversions/Relations/ByteStringAndTextArray.hs +1/−1
- src/library/LawfulConversions/Relations/ByteStringAndWord8List.hs +1/−1
- src/library/LawfulConversions/Relations/DayAndLazyText.hs +0/−15
- src/library/LawfulConversions/Relations/DayAndLazyTextBuilder.hs +0/−15
- src/library/LawfulConversions/Relations/DayAndStrictTextBuilder.hs +0/−36
- src/library/LawfulConversions/Relations/DayAndString.hs +0/−13
- src/library/LawfulConversions/Relations/DayAndText.hs +0/−14
- src/library/LawfulConversions/Relations/Int16AndWord16.hs +1/−1
- src/library/LawfulConversions/Relations/Int32AndWord32.hs +1/−1
- src/library/LawfulConversions/Relations/Int64AndWord64.hs +1/−1
- src/library/LawfulConversions/Relations/Int8AndWord8.hs +1/−1
- src/library/LawfulConversions/Relations/IntAndWord.hs +1/−1
- src/library/LawfulConversions/Relations/IntMapAndMapOfInt.hs +1/−1
- src/library/LawfulConversions/Relations/IntSetAndSetOfInt.hs +1/−1
- src/library/LawfulConversions/Relations/LazyByteStringAndLazyByteStringBuilder.hs +1/−1
- src/library/LawfulConversions/Relations/LazyByteStringAndLazyText.hs +0/−19
- src/library/LawfulConversions/Relations/LazyByteStringAndShortByteString.hs +1/−1
- src/library/LawfulConversions/Relations/LazyByteStringAndString.hs +0/−19
- src/library/LawfulConversions/Relations/LazyByteStringAndText.hs +0/−20
- src/library/LawfulConversions/Relations/LazyByteStringAndTextArray.hs +1/−1
- src/library/LawfulConversions/Relations/LazyByteStringAndWord8List.hs +1/−1
- src/library/LawfulConversions/Relations/LazyByteStringBuilderAndShortByteString.hs +1/−1
- src/library/LawfulConversions/Relations/LazyByteStringBuilderAndTextArray.hs +1/−1
- src/library/LawfulConversions/Relations/LazyByteStringBuilderAndWord8List.hs +1/−1
- src/library/LawfulConversions/Relations/LazyTextAndLazyTextBuilder.hs +1/−1
- src/library/LawfulConversions/Relations/LazyTextAndStrictTextBuilder.hs +2/−2
- src/library/LawfulConversions/Relations/LazyTextAndString.hs +2/−2
- src/library/LawfulConversions/Relations/LazyTextAndText.hs +1/−1
- src/library/LawfulConversions/Relations/LazyTextAndUtcTime.hs +0/−15
- src/library/LawfulConversions/Relations/LazyTextAndUuid.hs +0/−12
- src/library/LawfulConversions/Relations/LazyTextBuilderAndStrictTextBuilder.hs +2/−2
- src/library/LawfulConversions/Relations/LazyTextBuilderAndString.hs +2/−2
- src/library/LawfulConversions/Relations/LazyTextBuilderAndText.hs +1/−1
- src/library/LawfulConversions/Relations/LazyTextBuilderAndUtcTime.hs +0/−15
- src/library/LawfulConversions/Relations/LazyTextBuilderAndUuid.hs +0/−13
- src/library/LawfulConversions/Relations/ListAndSeq.hs +1/−1
- src/library/LawfulConversions/Relations/ShortByteStringAndTextArray.hs +1/−1
- src/library/LawfulConversions/Relations/ShortByteStringAndWord8List.hs +1/−1
- src/library/LawfulConversions/Relations/StrictTextBuilderAndString.hs +4/−4
- src/library/LawfulConversions/Relations/StrictTextBuilderAndText.hs +2/−2
- src/library/LawfulConversions/Relations/StrictTextBuilderAndUtcTime.hs +0/−36
- src/library/LawfulConversions/Relations/StrictTextBuilderAndUuid.hs +0/−28
- src/library/LawfulConversions/Relations/StringAndText.hs +2/−2
- src/library/LawfulConversions/Relations/StringAndUtcTime.hs +0/−13
- src/library/LawfulConversions/Relations/StringAndUuid.hs +0/−11
- src/library/LawfulConversions/Relations/TextAndUtcTime.hs +0/−14
- src/library/LawfulConversions/Relations/TextAndUuid.hs +0/−11
- src/library/LawfulConversions/Relations/TextArrayAndWord8List.hs +1/−1
- src/library/LawfulConversions/Relations/Void.hs +11/−0
- src/test/Main.hs +1/−22
CHANGELOG.md view
@@ -0,0 +1,19 @@+# v0.4++## Breaking++- Removed interpretation-based relations: UTF-8, ISO-8601, and UUID. + - Relations that depend on a specific encoding or format choice violate the library's principle of unambiguous structural conversion — there is no single canonical way to encode Text as bytes or render a UTCTime as a string.++# v0.3++## Breaking++- `from` of `IsMany` renamed to `onfrom`.+- New `from` function added, which is an alias to `to` with type arguments flipped.++# v0.2++## Breaking++- Added more tests in `isManyProperties` and an `Arbitrary` constraint on its parameter `a`.
lawful-conversions.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: lawful-conversions-version: 0.1.7+version: 0.4.0 synopsis: Lawful typeclasses for bidirectional conversion between types category: Conversion homepage: https://github.com/nikita-volkov/lawful-conversions@@ -50,6 +50,8 @@ evident what any of its instances do and it provides property-tests for you to validate your instances. + The laws and the concepts are based on set and category theories.+ = Prior work and acknowledgements This library is an offspring of the "[isomorphism-class](https://hackage.haskell.org/package/isomorphism-class)" library, expanding upon the patterns discovered there. Both libraries are maintained letting their designs compete.@@ -83,13 +85,14 @@ hs-source-dirs: src/library exposed-modules: LawfulConversions other-modules:- LawfulConversions.Classes+ LawfulConversions.Algebra LawfulConversions.Optics LawfulConversions.Prelude LawfulConversions.Properties LawfulConversions.Proxies LawfulConversions.Proxies.ViaIsSome LawfulConversions.Relations+ LawfulConversions.Relations.Any LawfulConversions.Relations.BoxedVectorAndList LawfulConversions.Relations.BoxedVectorAndSeq LawfulConversions.Relations.ByteArrayAndByteString@@ -100,17 +103,9 @@ LawfulConversions.Relations.ByteArrayAndWord8List LawfulConversions.Relations.ByteStringAndLazyByteString LawfulConversions.Relations.ByteStringAndLazyByteStringBuilder- LawfulConversions.Relations.ByteStringAndLazyText LawfulConversions.Relations.ByteStringAndShortByteString- LawfulConversions.Relations.ByteStringAndString- LawfulConversions.Relations.ByteStringAndText LawfulConversions.Relations.ByteStringAndTextArray LawfulConversions.Relations.ByteStringAndWord8List- LawfulConversions.Relations.DayAndLazyText- LawfulConversions.Relations.DayAndLazyTextBuilder- LawfulConversions.Relations.DayAndStrictTextBuilder- LawfulConversions.Relations.DayAndString- LawfulConversions.Relations.DayAndText LawfulConversions.Relations.Int16AndWord16 LawfulConversions.Relations.Int32AndWord32 LawfulConversions.Relations.Int64AndWord64@@ -119,10 +114,7 @@ LawfulConversions.Relations.IntMapAndMapOfInt LawfulConversions.Relations.IntSetAndSetOfInt LawfulConversions.Relations.LazyByteStringAndLazyByteStringBuilder- LawfulConversions.Relations.LazyByteStringAndLazyText LawfulConversions.Relations.LazyByteStringAndShortByteString- LawfulConversions.Relations.LazyByteStringAndString- LawfulConversions.Relations.LazyByteStringAndText LawfulConversions.Relations.LazyByteStringAndTextArray LawfulConversions.Relations.LazyByteStringAndWord8List LawfulConversions.Relations.LazyByteStringBuilderAndShortByteString@@ -132,40 +124,29 @@ LawfulConversions.Relations.LazyTextAndStrictTextBuilder LawfulConversions.Relations.LazyTextAndString LawfulConversions.Relations.LazyTextAndText- LawfulConversions.Relations.LazyTextAndUtcTime- LawfulConversions.Relations.LazyTextAndUuid LawfulConversions.Relations.LazyTextBuilderAndStrictTextBuilder LawfulConversions.Relations.LazyTextBuilderAndString LawfulConversions.Relations.LazyTextBuilderAndText- LawfulConversions.Relations.LazyTextBuilderAndUtcTime- LawfulConversions.Relations.LazyTextBuilderAndUuid LawfulConversions.Relations.ListAndSeq LawfulConversions.Relations.ShortByteStringAndTextArray LawfulConversions.Relations.ShortByteStringAndWord8List LawfulConversions.Relations.StrictTextBuilderAndString LawfulConversions.Relations.StrictTextBuilderAndText- LawfulConversions.Relations.StrictTextBuilderAndUtcTime- LawfulConversions.Relations.StrictTextBuilderAndUuid LawfulConversions.Relations.StringAndText- LawfulConversions.Relations.StringAndUtcTime- LawfulConversions.Relations.StringAndUuid- LawfulConversions.Relations.TextAndUtcTime- LawfulConversions.Relations.TextAndUuid LawfulConversions.Relations.TextArrayAndWord8List+ LawfulConversions.Relations.Void LawfulConversions.TextCompat.Array build-depends: QuickCheck >=2.13 && <3, base >=4.12 && <5, bytestring >=0.10 && <0.13,- containers >=0.6 && <0.8,+ containers >=0.6 && <0.9, hashable >=1 && <2, primitive >=0.7 && <0.10, profunctors >=5 && <6, text >=1.2 && <2.2,- time >=1.9 && <2, unordered-containers >=0.2 && <0.3,- uuid-types >=1.0 && <1.1, vector >=0.12 && <0.14, test-suite test@@ -179,7 +160,7 @@ bytestring >=0.11.1.0 && <0.13, lawful-conversions, primitive >=0.7 && <0.10,- quickcheck-instances >=0.3.32 && <0.4,+ quickcheck-instances >=0.3.32 && <0.5, rebase >=1.15 && <2, tasty >=1.2.3 && <2, tasty-quickcheck >=0.11 && <0.12,
src/library/LawfulConversions.hs view
@@ -15,7 +15,7 @@ -- > to @String :: IsSome String b => b -> String -- -- > > :t from @Text--- > from @Text :: IsMany Text b => Text -> b+-- > from @Text :: IsSome a Text => Text -> a -- -- In other words 'to' and 'from' let you explicitly specify either the source -- or the target type of a conversion when you need to help the type@@ -30,13 +30,6 @@ -- 'to' a <> 'to' b <> 'to' c -- @ ----- @--- renderNameAndHeight :: 'Text' -> 'Int' -> 'Text'--- renderNameAndHeight name height =--- 'from' @'Data.Text.Encoding.StrictTextBuilder' $--- "Height of " <> 'from' name <> " is " <> 'from' (show height)--- @--- -- = Partial conversions -- -- This library also captures the pattern of smart constructors via the 'IsSome' class, which associates a total 'to' conversion with its partial inverse 'maybeFrom'.@@ -72,7 +65,7 @@ -- You can also expand upon that and provide a default handling of invalid values effectively providing a lossy canonicalizing conversion ([Surjection](https://en.wikipedia.org/wiki/Surjective_function)): -- -- > instance IsMany Double Percent where--- > from double =+-- > onfrom double = -- > if double < 0 -- > then Percent 0 -- > else if double > 1@@ -88,6 +81,10 @@ Is, -- * Combinators+ from,+ maybeTo,+ tryFrom,+ tryTo, onto, -- * Optics@@ -105,7 +102,7 @@ ) where -import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Optics import LawfulConversions.Properties import LawfulConversions.Proxies
+ src/library/LawfulConversions/Algebra.hs view
@@ -0,0 +1,225 @@+module LawfulConversions.Algebra where++import LawfulConversions.Prelude++-- |+-- Evidence that all values of type @b@ form a subset of all values of type @a@.+--+-- [From Wikipedia](https://en.wikipedia.org/wiki/Subset):+--+-- In mathematics, a set A is a subset of a set B if all elements of A are also elements of B; B is then a superset of A. It is possible for A and B to be equal; if they are unequal, then A is a proper subset of B. The relationship of one set being a subset of another is called inclusion (or sometimes containment). A is a subset of B may also be expressed as B includes (or contains) A or A is included (or contained) in B. A k-subset is a subset with k elements.+--+-- === Laws+--+-- ==== 'to' is [injective](https://en.wikipedia.org/wiki/Injective_function)+--+-- For every two values of type @b@ that are not equal converting with 'to' produces values that are not equal as well:+--+-- > \(b1, b2) -> b1 == b2 || to @a b1 /= to @a b2+--+-- ==== 'maybeFrom' is a [partial inverse](https://en.wikipedia.org/wiki/Inverse_function#Partial_inverses) of 'to'+--+-- For all values of @b@ converting to @a@ and then attempting to convert back to @b@ always succeeds and produces a value that is equal to the original:+--+-- > \b -> maybeFrom (to @a b) == Just b+--+-- ==== 'maybeFrom' characterizes the image of 'to'+--+-- 'maybeFrom' succeeds exactly on values that are in the image of 'to':+--+-- > \a b -> maybeFrom a == Just b ==> to b == a+--+-- ==== Mathematical foundation+--+-- These laws establish that type @b@ forms a subset of type @a@ in the mathematical sense.+-- The 'to' function provides the canonical injection, while 'maybeFrom' recognizes which values of @a@+-- correspond to values from the subset @b@.+--+-- === Testing+--+-- For testing whether your instances conform to these laws use 'LawfulConversions.isSomeProperties'.+class IsSome a b where+ -- |+ -- Convert a value of a subset type to a superset type.+ to :: b -> a++ -- |+ -- [Partial inverse](https://en.wikipedia.org/wiki/Inverse_function#Partial_inverses) of 'to'.+ maybeFrom :: a -> Maybe b++ -- |+ -- Requires the presence of 'IsSome' in reverse direction.+ default maybeFrom :: (IsSome b a) => a -> Maybe b+ maybeFrom = Just . to++-- |+-- Convert a value of a subset type to a superset type, specifying the source subset type first.+--+-- Alias to 'to' with the only difference in the argument order.+--+-- E.g.,+--+-- > fromText = from @Text+from :: forall b a. (IsSome a b) => b -> a+from = to++-- |+-- Try to convert a value of a superset type to a subset type specifying the target subset type first.+--+-- Alias to 'maybeFrom' with the only difference in the argument order.+--+-- Particularly useful in combination with the @TypeApplications@ extension,+-- where it allows to specify the target type, e.g.:+--+-- > maybeToInt16 :: Int32 -> Maybe Int16+-- > maybeToInt16 = maybeTo @Int16+--+-- > percent = maybeTo @Percent someDouble+maybeTo :: forall b a. (IsSome a b) => a -> Maybe b+maybeTo = maybeFrom++-- |+-- Like 'maybeFrom', but returns an 'Either' with the provided error on failure.+--+-- Useful for raising custom errors when conversion fails.+tryFrom :: (IsSome a b) => e -> a -> Either e b+tryFrom err a =+ case maybeFrom a of+ Just b -> Right b+ Nothing -> Left err++-- |+-- Alias to 'tryFrom', which lets you specify the target type of the conversion first using @TypeApplications@.+tryTo :: forall b a e. (IsSome a b) => e -> a -> Either e b+tryTo = tryFrom++-- |+-- Lossy or canonicalizing conversion.+-- Captures mappings from multiple alternative inputs into one output.+--+-- E.g.,+--+-- - `ByteString` can be decoded into `Text` with UTF-8 leniently, replacing the invalid chars with a default char.+--+-- - `String` has a wider range of supported chars than `Text`, so some chars get replaced too.+--+-- === Laws+--+-- ==== 'onfrom' is an [inverse](https://en.wikipedia.org/wiki/Inverse_function) of 'to'+--+-- > \b -> b == onfrom (to @a b)+--+-- ==== 'onfrom' is [surjective](https://en.wikipedia.org/wiki/Surjective_function)+--+-- Every value of type @b@ can be obtained by applying 'onfrom' to some value of type @a@:+--+-- > \b -> exists a. onfrom @a @b a == b+--+-- Note: This property cannot be directly tested with QuickCheck as it requires existential quantification.+--+-- ==== Law hierarchy+--+-- 'IsMany' extends 'IsSome', so all laws from 'IsSome' also apply here.+-- The combination ensures that 'onfrom' provides a canonical (possibly lossy) conversion from @a@ to @b@,+-- while 'to' provides the lossless injection from @b@ to @a@.+--+-- === Testing+--+-- For testing whether your instances conform to these laws use 'LawfulConversions.isManyProperties'.+class (IsSome a b) => IsMany a b where+ -- |+ -- Possibly lossy inverse of 'to'.+ -- [Surjection](https://en.wikipedia.org/wiki/Surjective_function) from @a@ to @b@.+ --+ -- Particularly useful in combination with the @TypeApplications@ extension,+ -- where it allows to specify the input type, e.g.:+ --+ -- > fromString :: IsMany String b => String -> b+ -- > fromString = onfrom @String+ --+ -- If you want to specify the output type instead, use 'onto'.+ onfrom :: a -> b++ -- |+ -- Requires the presence of 'IsSome' in reverse direction.+ default onfrom :: (IsSome b a) => a -> b+ onfrom = to++-- |+-- Alias to 'onfrom', which lets you specify the target type of the conversion first using @TypeApplications@.+--+-- In mathematics @onto@ is another name for [Surjective function](https://en.wikipedia.org/wiki/Surjective_function).+--+-- E.g.,+--+-- > lenientDecodeUtf8 = onto @Text+--+-- @+-- combineTexts :: 'Text' -> 'ByteString' -> 'Int' -> 'Text'+-- combineTexts name email height =+-- 'from' @'Data.Text.Encoding.StrictTextBuilder' $+-- "Height of " <> 'to' name <> " is " <> 'onto' (show height) <> " and email is " <> 'onto' email+-- @+onto :: forall b a. (IsMany a b) => a -> b+onto = onfrom++-- | Bidirectional conversion between two types with no loss of information.+--+-- The bidirectionality is encoded via a recursive dependency with arguments+-- flipped.+--+-- You can read the signature @Is a b@ as \"/B/ is /A/\".+--+-- === Laws+--+-- ==== 'from' is an [inverse](https://en.wikipedia.org/wiki/Inverse_function) of 'to'+--+-- For all values of /b/ converting from /b/ to /a/ and then converting from /a/ to /b/ produces the original value:+--+-- > \b -> b == from @a (to @a b)+--+-- ==== 'to' is an [inverse](https://en.wikipedia.org/wiki/Inverse_function) of 'from'+--+-- For all values of /a/ converting from /a/ to /b/ and then converting from /b/ to /a/ produces the original value:+--+-- > \a -> a == to @a (from @a @b a)+--+-- ==== Mathematical relationship+--+-- These two laws together establish that 'to' and 'from' form a true [isomorphism](https://en.wikipedia.org/wiki/Isomorphism) between types @a@ and @b@.+-- Note that 'from' is implemented as 'to' from the reverse 'Is' instance, ensuring the symmetry required for isomorphisms.+--+-- ==== 'from' equals 'onfrom'+--+-- For isomorphic types, both ways of converting should be equivalent:+--+-- > \a -> from @a @b a == onfrom @a @b a+--+-- === Testing+--+-- For testing whether your instances conform to these laws use 'LawfulConversions.isProperties'.+--+-- === Instance Definition+--+-- For each pair of isomorphic types (/A/ and /B/) the compiler will require you to define six instances, namely: @Is A B@ and @Is B A@, @IsMany A B@ and @IsMany B A@, @IsSome A B@ and @IsSome B A@.+--+-- Instances of @Is@ do not define any functions and serve merely as a statement that the laws are satisfied.+--+-- ==== Example: Lazy Text and Text+--+-- @+-- instance IsSome "Data.Text.Lazy.LazyText" "Data.Text.Text" where+-- to = LazyText.'Data.Text.Lazy.fromStrict'+--+-- instance IsSome "Data.Text.Text" "Data.Text.Lazy.LazyText" where+-- to = LazyText.'Data.Text.Lazy.toStrict'+--+-- instance IsMany "Data.Text.Lazy.LazyText" "Data.Text.Text"+--+-- instance IsMany "Data.Text.Text" "Data.Text.Lazy.LazyText"+--+-- instance Is "Data.Text.Lazy.LazyText" "Data.Text.Text"+--+-- instance Is "Data.Text.Text" "Data.Text.Lazy.LazyText"+-- @+class (IsMany a b, Is b a) => Is a b
− src/library/LawfulConversions/Classes.hs
@@ -1,158 +0,0 @@-module LawfulConversions.Classes where--import LawfulConversions.Prelude---- |--- Evidence that all values of type @b@ form a subset of all values of type @a@.------ [From Wikipedia](https://en.wikipedia.org/wiki/Subset):------ In mathematics, a set A is a subset of a set B if all elements of A are also elements of B; B is then a superset of A. It is possible for A and B to be equal; if they are unequal, then A is a proper subset of B. The relationship of one set being a subset of another is called inclusion (or sometimes containment). A is a subset of B may also be expressed as B includes (or contains) A or A is included (or contained) in B. A k-subset is a subset with k elements.------ === Laws------ ==== 'to' is [injective](https://en.wikipedia.org/wiki/Injective_function)------ For every two values of type @b@ that are not equal converting with 'to' produces values that are not equal as well:------ > \(b1, b2) -> b1 == b2 || to @a b1 /= to @a b2------ ==== 'maybeFrom' is a [partial inverse](https://en.wikipedia.org/wiki/Inverse_function#Partial_inverses) of 'to'------ For all values of @b@ converting to @a@ and then attempting to convert back to @b@ always succeeds and produces a value that is equal to the original:------ > \b -> maybeFrom (to @a b) == Just b------ === Testing------ For testing whether your instances conform to these laws use 'LawfulConversions.isSomeProperties'.-class IsSome a b where- -- |- -- Convert a value of a subset type to a superset type.- to :: b -> a-- -- |- -- [Partial inverse](https://en.wikipedia.org/wiki/Inverse_function#Partial_inverses) of 'to'.- maybeFrom :: a -> Maybe b-- -- |- -- Requires the presence of 'IsSome' in reverse direction.- default maybeFrom :: (IsSome b a) => a -> Maybe b- maybeFrom = Just . to---- | Every type is isomorphic to itself.-instance IsSome a a where- to = id- maybeFrom = Just . id---- | The empty set has no elements, and therefore is vacuously a subset of any set.-instance IsSome a Void where- to = absurd- maybeFrom = const Nothing---- |--- Lossy or canonicalizing conversion.--- Captures mappings from multiple alternative inputs into one output.------ E.g.,------ - `ByteString` can be decoded into `Text` with UTF-8 leniently, replacing the invalid chars with a default char.------ - `String` has a wider range of supported chars than `Text`, so some chars get replaced too.------ === Laws------ ==== 'from' is an [inverse](https://en.wikipedia.org/wiki/Inverse_function) of 'to'------ > \b -> b == from (to @a b)------ === Testing------ For testing whether your instances conform to these laws use 'LawfulConversions.isManyProperties'.-class (IsSome a b) => IsMany a b where- -- |- -- Possibly lossy inverse of 'to'.- -- [Surjection](https://en.wikipedia.org/wiki/Surjective_function) from @a@ to @b@.- --- -- Particularly useful in combination with the @TypeApplications@ extension,- -- where it allows to specify the input type, e.g.:- --- -- > fromText :: IsMany Text b => Text -> b- -- > fromText = from @Text- --- -- The first type application of the 'to' function on the other hand specifies- -- the output data type.- --- -- If you want to specify the output type instead, use 'onto'.- from :: a -> b-- -- |- -- Requires the presence of 'IsSome' in reverse direction.- default from :: (IsSome b a) => a -> b- from = to---- |--- Alias to 'from', which lets you specify the target type of the conversion first using @TypeApplications@.------ In mathematics @onto@ is another name for [Surjective function](https://en.wikipedia.org/wiki/Surjective_function).------ E.g.,------ > lenientDecodeUtf8 = onto @Text-onto :: forall b a. (IsMany a b) => a -> b-onto = from--instance IsMany a a---- | Bidirectional conversion between two types with no loss of information.------ The bidirectionality is encoded via a recursive dependency with arguments--- flipped.------ You can read the signature @Is a b@ as \"/B/ is /A/\".------ === Laws------ ==== 'from' is an [inverse](https://en.wikipedia.org/wiki/Inverse_function) of 'to'------ For all values of /b/ converting from /b/ to /a/ and then converting from /a/ to /b/ produces the original value:------ > \b -> b == from (to @a b)------ ==== 'to' is an [inverse](https://en.wikipedia.org/wiki/Inverse_function) of 'from'------ For all values of /a/ converting from /a/ to /b/ and then converting from /b/ to /a/ produces the original value:------ > \a -> a == to (from @a @b a)------ === Testing------ For testing whether your instances conform to these laws use 'LawfulConversions.isProperties'.------ === Instance Definition------ For each pair of isomorphic types (/A/ and /B/) the compiler will require you to define six instances, namely: @Is A B@ and @Is B A@, @IsMany A B@ and @IsMany B A@, @IsSome A B@ and @IsSome B A@.------ Instances of @Is@ do not define any functions and serve merely as a statement that the laws are satisfied.------ ==== Example: Lazy Text and Text------ @--- instance IsSome "Data.Text.Lazy.LazyText" "Data.Text.Text" where--- to = LazyText.'Data.Text.Lazy.fromStrict'------ instance IsSome "Data.Text.Text" "Data.Text.Lazy.LazyText" where--- to = LazyText.'Data.Text.Lazy.toStrict'------ instance IsMany "Data.Text.Lazy.LazyText" "Data.Text.Text"------ instance IsMany "Data.Text.Text" "Data.Text.Lazy.LazyText"------ instance Is "Data.Text.Lazy.LazyText" "Data.Text.Text"------ instance Is "Data.Text.Text" "Data.Text.Lazy.LazyText"--- @-class (IsMany a b, Is b a) => Is a b---- | Any type is isomorphic to itself.-instance Is a a
src/library/LawfulConversions/Optics.hs view
@@ -1,7 +1,7 @@ module LawfulConversions.Optics where import Data.Profunctor-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude -- | Van-Laarhoven-style Prism, compatible with libraries like \"lens\" and \"optics\".@@ -14,7 +14,7 @@ -- | Van-Laarhoven-style Isomorphism, compatible with libraries like \"lens\" and \"optics\". isManyIso :: (IsMany a b, Profunctor p, Functor f) => p b (f b) -> p a (f a)-isManyIso = dimap from (fmap to)+isManyIso = dimap onfrom (fmap to) -- | Van-Laarhoven-style Isomorphism, compatible with libraries like \"lens\" and \"optics\". isIso :: (Is a b, Profunctor p, Functor f) => p b (f b) -> p a (f a)
src/library/LawfulConversions/Prelude.hs view
@@ -55,7 +55,6 @@ import Data.Text as Exports (Text) import Data.Traversable as Exports import Data.Tuple as Exports-import Data.UUID.Types as Exports (UUID) import Data.Vector as Exports (Vector) import Data.Version as Exports import Data.Void as Exports
src/library/LawfulConversions/Properties.hs view
@@ -5,7 +5,7 @@ ) where -import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import Test.QuickCheck @@ -22,19 +22,27 @@ -- > (uncurry prop) -- > (isSomeProperties @Int32 @Int16 Proxy Proxy) isSomeProperties ::- (IsSome a b, Eq a, Eq b, Show a, Show b, Arbitrary b) =>+ forall a b.+ (IsSome a b, Eq a, Eq b, Show a, Show b, Arbitrary a, Arbitrary b) => Proxy a -> Proxy b -> [(String, Property)] isSomeProperties aProxy bProxy = [ ( "'to' is injective",- property \a b ->- a /= b ==>- to' a =/= to' b+ property \b1 b2 ->+ if b1 == b2+ then property True+ else to' b1 =/= to' b2 ), ( "'maybeFrom' is a partial inverse of 'to'",+ property \b ->+ maybeFrom' (to' b) === Just b+ ),+ ( "'maybeFrom' characterizes the image of 'to'", property \a ->- maybeFrom' (to' a) === Just a+ case maybeFrom' a of+ Just b -> to' b === a+ Nothing -> property True ) ] where@@ -54,18 +62,30 @@ -- > (uncurry prop) -- > (isManyProperties @String @Text Proxy Proxy) isManyProperties ::- (IsMany a b, Eq a, Eq b, Show a, Show b, Arbitrary b) =>+ forall a b.+ (IsMany a b, Eq a, Eq b, Show a, Show b, Arbitrary a, Arbitrary b) => Proxy a -> Proxy b -> [(String, Property)] isManyProperties aProxy bProxy =- ( "'from' is an inverse of 'to'",- property \b -> b === from' (to' b)- )- : isSomeProperties aProxy bProxy+ [ ( "'onfrom' is an inverse of 'to'",+ property \b -> b === onfrom' (to' b)+ ),+ ( "'onfrom' is consistent with 'maybeFrom'",+ property \(b :: b) ->+ let a = to @a b+ in maybeFrom (to @a b) === Just (onfrom @a @b a)+ ),+ ( "'to' after 'onfrom' always succeeds with 'maybeFrom'",+ property \a ->+ let b = onfrom' a+ in maybeFrom (to' b) === Just b+ )+ ]+ <> isSomeProperties aProxy bProxy where to' = as aProxy . to . as bProxy- from' = as bProxy . from . as aProxy+ onfrom' = as bProxy . onfrom . as aProxy -- | -- Properties testing whether an instance satisfies the laws of 'Is'.@@ -85,10 +105,15 @@ Proxy b -> [(String, Property)] isProperties aProxy bProxy =- ( "'to' is an inverse of 'from'",- property \b -> b === to' (from' b)- )- : isManyProperties aProxy bProxy+ [ ( "'to' is an inverse of 'from'",+ property \b -> b === to' (from' b)+ ),+ ( "'from' equals 'onfrom'",+ property \a -> from' a === onfrom' a+ )+ ]+ <> isManyProperties aProxy bProxy where to' = as aProxy . to . as bProxy from' = as bProxy . from . as aProxy+ onfrom' = as bProxy . onfrom . as aProxy
src/library/LawfulConversions/Proxies/ViaIsSome.hs view
@@ -1,6 +1,6 @@ module LawfulConversions.Proxies.ViaIsSome where -import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import qualified Test.QuickCheck as QuickCheck
src/library/LawfulConversions/Relations.hs view
@@ -1,5 +1,6 @@ module LawfulConversions.Relations () where +import LawfulConversions.Relations.Any () import LawfulConversions.Relations.BoxedVectorAndList () import LawfulConversions.Relations.BoxedVectorAndSeq () import LawfulConversions.Relations.ByteArrayAndByteString ()@@ -10,17 +11,9 @@ import LawfulConversions.Relations.ByteArrayAndWord8List () import LawfulConversions.Relations.ByteStringAndLazyByteString () import LawfulConversions.Relations.ByteStringAndLazyByteStringBuilder ()-import LawfulConversions.Relations.ByteStringAndLazyText () import LawfulConversions.Relations.ByteStringAndShortByteString ()-import LawfulConversions.Relations.ByteStringAndString ()-import LawfulConversions.Relations.ByteStringAndText () import LawfulConversions.Relations.ByteStringAndTextArray () import LawfulConversions.Relations.ByteStringAndWord8List ()-import LawfulConversions.Relations.DayAndLazyText ()-import LawfulConversions.Relations.DayAndLazyTextBuilder ()-import LawfulConversions.Relations.DayAndStrictTextBuilder ()-import LawfulConversions.Relations.DayAndString ()-import LawfulConversions.Relations.DayAndText () import LawfulConversions.Relations.Int16AndWord16 () import LawfulConversions.Relations.Int32AndWord32 () import LawfulConversions.Relations.Int64AndWord64 ()@@ -29,10 +22,7 @@ import LawfulConversions.Relations.IntMapAndMapOfInt () import LawfulConversions.Relations.IntSetAndSetOfInt () import LawfulConversions.Relations.LazyByteStringAndLazyByteStringBuilder ()-import LawfulConversions.Relations.LazyByteStringAndLazyText () import LawfulConversions.Relations.LazyByteStringAndShortByteString ()-import LawfulConversions.Relations.LazyByteStringAndString ()-import LawfulConversions.Relations.LazyByteStringAndText () import LawfulConversions.Relations.LazyByteStringAndTextArray () import LawfulConversions.Relations.LazyByteStringAndWord8List () import LawfulConversions.Relations.LazyByteStringBuilderAndShortByteString ()@@ -42,23 +32,14 @@ import LawfulConversions.Relations.LazyTextAndStrictTextBuilder () import LawfulConversions.Relations.LazyTextAndString () import LawfulConversions.Relations.LazyTextAndText ()-import LawfulConversions.Relations.LazyTextAndUtcTime ()-import LawfulConversions.Relations.LazyTextAndUuid () import LawfulConversions.Relations.LazyTextBuilderAndStrictTextBuilder () import LawfulConversions.Relations.LazyTextBuilderAndString () import LawfulConversions.Relations.LazyTextBuilderAndText ()-import LawfulConversions.Relations.LazyTextBuilderAndUtcTime ()-import LawfulConversions.Relations.LazyTextBuilderAndUuid () import LawfulConversions.Relations.ListAndSeq () import LawfulConversions.Relations.ShortByteStringAndTextArray () import LawfulConversions.Relations.ShortByteStringAndWord8List () import LawfulConversions.Relations.StrictTextBuilderAndString () import LawfulConversions.Relations.StrictTextBuilderAndText ()-import LawfulConversions.Relations.StrictTextBuilderAndUtcTime ()-import LawfulConversions.Relations.StrictTextBuilderAndUuid () import LawfulConversions.Relations.StringAndText ()-import LawfulConversions.Relations.StringAndUtcTime ()-import LawfulConversions.Relations.StringAndUuid ()-import LawfulConversions.Relations.TextAndUtcTime ()-import LawfulConversions.Relations.TextAndUuid () import LawfulConversions.Relations.TextArrayAndWord8List ()+import LawfulConversions.Relations.Void ()
+ src/library/LawfulConversions/Relations/Any.hs view
@@ -0,0 +1,17 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module LawfulConversions.Relations.Any where++import LawfulConversions.Algebra+import LawfulConversions.Prelude++-- | Any type is isomorphic to itself.+instance IsSome a a where+ to = id+ maybeFrom = Just . id++-- | Any type is isomorphic to itself.+instance IsMany a a++-- | Any type is isomorphic to itself.+instance Is a a
src/library/LawfulConversions/Relations/BoxedVectorAndList.hs view
@@ -3,7 +3,7 @@ module LawfulConversions.Relations.BoxedVectorAndList where import qualified Data.Vector-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome (Vector a) [a] where
src/library/LawfulConversions/Relations/BoxedVectorAndSeq.hs view
@@ -4,7 +4,7 @@ import qualified Data.Sequence import qualified Data.Vector-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome (Vector a) (Seq a) where
src/library/LawfulConversions/Relations/ByteArrayAndByteString.hs view
@@ -4,7 +4,7 @@ import qualified Data.ByteString.Short import qualified Data.Primitive.ByteArray-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import LawfulConversions.Relations.ByteArrayAndShortByteString () import LawfulConversions.Relations.ByteStringAndShortByteString ()
src/library/LawfulConversions/Relations/ByteArrayAndLazyByteString.hs view
@@ -5,7 +5,7 @@ import qualified Data.ByteString.Lazy import qualified Data.ByteString.Short import qualified Data.Primitive.ByteArray-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import LawfulConversions.Relations.ByteArrayAndShortByteString () import LawfulConversions.Relations.LazyByteStringAndShortByteString ()
src/library/LawfulConversions/Relations/ByteArrayAndLazyByteStringBuilder.hs view
@@ -5,7 +5,7 @@ import qualified Data.ByteString.Builder import qualified Data.ByteString.Short import qualified Data.Primitive.ByteArray-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import LawfulConversions.Relations.ByteArrayAndShortByteString () import LawfulConversions.Relations.LazyByteStringBuilderAndShortByteString ()
src/library/LawfulConversions/Relations/ByteArrayAndShortByteString.hs view
@@ -5,7 +5,7 @@ import qualified Data.ByteString.Short import qualified Data.ByteString.Short.Internal import qualified Data.Primitive.ByteArray-import LawfulConversions.Classes+import LawfulConversions.Algebra instance IsSome Data.ByteString.Short.ShortByteString Data.Primitive.ByteArray.ByteArray where to (Data.Primitive.ByteArray.ByteArray array) =
src/library/LawfulConversions/Relations/ByteArrayAndTextArray.hs view
@@ -7,7 +7,7 @@ import qualified Data.Primitive.ByteArray import qualified Data.Text.Array-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import qualified LawfulConversions.TextCompat.Array
src/library/LawfulConversions/Relations/ByteArrayAndWord8List.hs view
@@ -3,7 +3,7 @@ module LawfulConversions.Relations.ByteArrayAndWord8List where import qualified Data.Primitive.ByteArray-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import LawfulConversions.Relations.ByteArrayAndShortByteString ()
src/library/LawfulConversions/Relations/ByteStringAndLazyByteString.hs view
@@ -3,7 +3,7 @@ module LawfulConversions.Relations.ByteStringAndLazyByteString where import qualified Data.ByteString.Lazy-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome ByteString Data.ByteString.Lazy.ByteString where
src/library/LawfulConversions/Relations/ByteStringAndLazyByteStringBuilder.hs view
@@ -4,7 +4,7 @@ import qualified Data.ByteString.Builder import qualified Data.ByteString.Lazy-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome ByteString Data.ByteString.Builder.Builder where
− src/library/LawfulConversions/Relations/ByteStringAndLazyText.hs
@@ -1,19 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.ByteStringAndLazyText where--import qualified Data.ByteString.Lazy-import qualified Data.Text.Encoding.Error-import qualified Data.Text.Lazy-import qualified Data.Text.Lazy.Encoding-import LawfulConversions.Classes-import LawfulConversions.Prelude---- | UTF-8 codec.-instance IsSome ByteString Data.Text.Lazy.Text where- to = Data.ByteString.Lazy.toStrict . Data.Text.Lazy.Encoding.encodeUtf8- maybeFrom = either (const Nothing) Just . Data.Text.Lazy.Encoding.decodeUtf8' . Data.ByteString.Lazy.fromStrict---- | Lenient UTF-8 decoding.-instance IsMany ByteString Data.Text.Lazy.Text where- from = Data.Text.Lazy.Encoding.decodeUtf8With Data.Text.Encoding.Error.lenientDecode . Data.ByteString.Lazy.fromStrict
src/library/LawfulConversions/Relations/ByteStringAndShortByteString.hs view
@@ -3,7 +3,7 @@ module LawfulConversions.Relations.ByteStringAndShortByteString where import qualified Data.ByteString.Short-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome ByteString Data.ByteString.Short.ShortByteString where
− src/library/LawfulConversions/Relations/ByteStringAndString.hs
@@ -1,18 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.ByteStringAndString where--import qualified Data.Text-import qualified Data.Text.Encoding-import qualified Data.Text.Encoding.Error-import LawfulConversions.Classes-import LawfulConversions.Prelude---- | UTF-8 codec.-instance IsSome ByteString String where- to = Data.Text.Encoding.encodeUtf8 . Data.Text.pack- maybeFrom = either (const Nothing) (Just . Data.Text.unpack) . Data.Text.Encoding.decodeUtf8'---- | Lenient UTF-8 decoding.-instance IsMany ByteString String where- from = Data.Text.unpack . Data.Text.Encoding.decodeUtf8With Data.Text.Encoding.Error.lenientDecode
− src/library/LawfulConversions/Relations/ByteStringAndText.hs
@@ -1,17 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.ByteStringAndText where--import qualified Data.Text.Encoding-import qualified Data.Text.Encoding.Error-import LawfulConversions.Classes-import LawfulConversions.Prelude---- | UTF-8 codec.-instance IsSome ByteString Text where- to = Data.Text.Encoding.encodeUtf8- maybeFrom = either (const Nothing) Just . Data.Text.Encoding.decodeUtf8'---- | Lenient UTF-8 decoding.-instance IsMany ByteString Text where- from = Data.Text.Encoding.decodeUtf8With Data.Text.Encoding.Error.lenientDecode
src/library/LawfulConversions/Relations/ByteStringAndTextArray.hs view
@@ -7,7 +7,7 @@ import qualified Data.ByteString.Short import qualified Data.Text.Array-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import qualified LawfulConversions.TextCompat.Array
src/library/LawfulConversions/Relations/ByteStringAndWord8List.hs view
@@ -3,7 +3,7 @@ module LawfulConversions.Relations.ByteStringAndWord8List where import qualified Data.ByteString-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome ByteString [Word8] where
− src/library/LawfulConversions/Relations/DayAndLazyText.hs
@@ -1,15 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.DayAndLazyText where--import qualified Data.Text.Lazy-import Data.Time-import LawfulConversions.Classes-import LawfulConversions.Prelude-import LawfulConversions.Relations.DayAndString ()-import LawfulConversions.Relations.LazyTextAndString ()---- | Implements ISO-8601.-instance IsSome Data.Text.Lazy.Text Day where- to = fromString . to- maybeFrom = maybeFrom @String . to
− src/library/LawfulConversions/Relations/DayAndLazyTextBuilder.hs
@@ -1,15 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.DayAndLazyTextBuilder where--import qualified Data.Text.Lazy.Builder-import Data.Time-import LawfulConversions.Classes-import LawfulConversions.Prelude-import LawfulConversions.Relations.DayAndString ()-import LawfulConversions.Relations.LazyTextBuilderAndString ()---- | Implements ISO-8601.-instance IsSome Data.Text.Lazy.Builder.Builder Day where- to = fromString . to- maybeFrom = maybeFrom @String . to
− src/library/LawfulConversions/Relations/DayAndStrictTextBuilder.hs
@@ -1,36 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.DayAndStrictTextBuilder where--#if MIN_VERSION_text(2,1,2)--import qualified Data.Text.Encoding-import Data.Time-import LawfulConversions.Classes-import LawfulConversions.Prelude-import LawfulConversions.Relations.StrictTextBuilderAndString ()-import LawfulConversions.Relations.StringAndText ()-import LawfulConversions.Relations.DayAndString ()---- | Implements ISO-8601.-instance IsSome Data.Text.Encoding.StrictTextBuilder Day where- to = from . to @String- maybeFrom = maybeFrom @String . to--#elif MIN_VERSION_text(2,0,2)--import qualified Data.Text.Encoding-import Data.Time-import LawfulConversions.Classes-import LawfulConversions.Prelude-import LawfulConversions.Relations.StrictTextBuilderAndString ()-import LawfulConversions.Relations.StringAndText ()-import LawfulConversions.Relations.DayAndString ()---- | Implements ISO-8601.-instance IsSome Data.Text.Encoding.StrictBuilder Day where- to = from . to @String- maybeFrom = maybeFrom @String . to--#endif
− src/library/LawfulConversions/Relations/DayAndString.hs
@@ -1,13 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.DayAndString where--import Data.Time-import Data.Time.Format.ISO8601-import LawfulConversions.Classes-import LawfulConversions.Prelude---- | Implements ISO-8601.-instance IsSome String Day where- to = iso8601Show- maybeFrom = iso8601ParseM
− src/library/LawfulConversions/Relations/DayAndText.hs
@@ -1,14 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.DayAndText where--import Data.Time-import LawfulConversions.Classes-import LawfulConversions.Prelude-import LawfulConversions.Relations.DayAndString ()-import LawfulConversions.Relations.StringAndText ()---- | Implements ISO-8601.-instance IsSome Text Day where- to = fromString . to- maybeFrom = maybeFrom @String . to
src/library/LawfulConversions/Relations/Int16AndWord16.hs view
@@ -2,7 +2,7 @@ module LawfulConversions.Relations.Int16AndWord16 where -import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Int16 Word16 where
src/library/LawfulConversions/Relations/Int32AndWord32.hs view
@@ -2,7 +2,7 @@ module LawfulConversions.Relations.Int32AndWord32 where -import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Int32 Word32 where
src/library/LawfulConversions/Relations/Int64AndWord64.hs view
@@ -2,7 +2,7 @@ module LawfulConversions.Relations.Int64AndWord64 where -import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Int64 Word64 where
src/library/LawfulConversions/Relations/Int8AndWord8.hs view
@@ -2,7 +2,7 @@ module LawfulConversions.Relations.Int8AndWord8 where -import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Int8 Word8 where
src/library/LawfulConversions/Relations/IntAndWord.hs view
@@ -2,7 +2,7 @@ module LawfulConversions.Relations.IntAndWord where -import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Int Word where
src/library/LawfulConversions/Relations/IntMapAndMapOfInt.hs view
@@ -4,7 +4,7 @@ import qualified Data.IntMap.Strict import qualified Data.Map.Strict-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome (Map Int v) (IntMap v) where
src/library/LawfulConversions/Relations/IntSetAndSetOfInt.hs view
@@ -2,7 +2,7 @@ module LawfulConversions.Relations.IntSetAndSetOfInt where -import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome (Set Int) IntSet where
src/library/LawfulConversions/Relations/LazyByteStringAndLazyByteStringBuilder.hs view
@@ -4,7 +4,7 @@ import qualified Data.ByteString.Builder import qualified Data.ByteString.Lazy-import LawfulConversions.Classes+import LawfulConversions.Algebra instance IsSome Data.ByteString.Lazy.ByteString Data.ByteString.Builder.Builder where to = Data.ByteString.Builder.toLazyByteString
− src/library/LawfulConversions/Relations/LazyByteStringAndLazyText.hs
@@ -1,19 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.LazyByteStringAndLazyText where--import qualified Data.ByteString.Lazy-import qualified Data.Text.Encoding.Error-import qualified Data.Text.Lazy-import qualified Data.Text.Lazy.Encoding-import LawfulConversions.Classes-import LawfulConversions.Prelude---- | UTF-8 codec.-instance IsSome Data.ByteString.Lazy.ByteString Data.Text.Lazy.Text where- to = Data.Text.Lazy.Encoding.encodeUtf8- maybeFrom = either (const Nothing) Just . Data.Text.Lazy.Encoding.decodeUtf8'---- | Lenient UTF-8 decoding.-instance IsMany Data.ByteString.Lazy.ByteString Data.Text.Lazy.Text where- from = Data.Text.Lazy.Encoding.decodeUtf8With Data.Text.Encoding.Error.lenientDecode
src/library/LawfulConversions/Relations/LazyByteStringAndShortByteString.hs view
@@ -4,7 +4,7 @@ import qualified Data.ByteString.Lazy import qualified Data.ByteString.Short-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Data.ByteString.Lazy.ByteString Data.ByteString.Short.ShortByteString where
− src/library/LawfulConversions/Relations/LazyByteStringAndString.hs
@@ -1,19 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.LazyByteStringAndString where--import qualified Data.ByteString.Lazy-import qualified Data.Text.Encoding.Error-import qualified Data.Text.Lazy-import qualified Data.Text.Lazy.Encoding-import LawfulConversions.Classes-import LawfulConversions.Prelude---- | UTF-8 codec.-instance IsSome Data.ByteString.Lazy.ByteString String where- to = Data.Text.Lazy.Encoding.encodeUtf8 . Data.Text.Lazy.pack- maybeFrom = either (const Nothing) (Just . Data.Text.Lazy.unpack) . Data.Text.Lazy.Encoding.decodeUtf8'---- | Lenient UTF-8 decoding.-instance IsMany Data.ByteString.Lazy.ByteString String where- from = Data.Text.Lazy.unpack . Data.Text.Lazy.Encoding.decodeUtf8With Data.Text.Encoding.Error.lenientDecode
− src/library/LawfulConversions/Relations/LazyByteStringAndText.hs
@@ -1,20 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.LazyByteStringAndText where--import qualified Data.ByteString.Lazy-import qualified Data.Text-import qualified Data.Text.Encoding.Error-import qualified Data.Text.Lazy-import qualified Data.Text.Lazy.Encoding-import LawfulConversions.Classes-import LawfulConversions.Prelude---- | UTF-8 codec.-instance IsSome Data.ByteString.Lazy.ByteString Data.Text.Text where- to = Data.Text.Lazy.Encoding.encodeUtf8 . Data.Text.Lazy.fromStrict- maybeFrom = either (const Nothing) (Just . Data.Text.Lazy.toStrict) . Data.Text.Lazy.Encoding.decodeUtf8'---- | Lenient UTF-8 decoding.-instance IsMany Data.ByteString.Lazy.ByteString Data.Text.Text where- from = Data.Text.Lazy.toStrict . Data.Text.Lazy.Encoding.decodeUtf8With Data.Text.Encoding.Error.lenientDecode
src/library/LawfulConversions/Relations/LazyByteStringAndTextArray.hs view
@@ -8,7 +8,7 @@ import qualified Data.ByteString.Lazy import qualified Data.ByteString.Short import qualified Data.Text.Array-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import qualified LawfulConversions.TextCompat.Array
src/library/LawfulConversions/Relations/LazyByteStringAndWord8List.hs view
@@ -3,7 +3,7 @@ module LawfulConversions.Relations.LazyByteStringAndWord8List where import qualified Data.ByteString.Lazy-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Data.ByteString.Lazy.ByteString [Word8] where
src/library/LawfulConversions/Relations/LazyByteStringBuilderAndShortByteString.hs view
@@ -5,7 +5,7 @@ import qualified Data.ByteString.Builder import qualified Data.ByteString.Lazy import qualified Data.ByteString.Short-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Data.ByteString.Builder.Builder Data.ByteString.Short.ShortByteString where
src/library/LawfulConversions/Relations/LazyByteStringBuilderAndTextArray.hs view
@@ -9,7 +9,7 @@ import qualified Data.ByteString.Lazy import qualified Data.ByteString.Short import qualified Data.Text.Array-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import qualified LawfulConversions.TextCompat.Array
src/library/LawfulConversions/Relations/LazyByteStringBuilderAndWord8List.hs view
@@ -4,7 +4,7 @@ import qualified Data.ByteString.Builder import qualified Data.ByteString.Lazy-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Data.ByteString.Builder.Builder [Word8] where
src/library/LawfulConversions/Relations/LazyTextAndLazyTextBuilder.hs view
@@ -4,7 +4,7 @@ import qualified Data.Text.Lazy import qualified Data.Text.Lazy.Builder-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Data.Text.Lazy.Text Data.Text.Lazy.Builder.Builder where
src/library/LawfulConversions/Relations/LazyTextAndStrictTextBuilder.hs view
@@ -7,7 +7,7 @@ import qualified Data.Text.Encoding import qualified Data.Text.Lazy-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Data.Text.Lazy.Text Data.Text.Encoding.StrictTextBuilder where@@ -28,7 +28,7 @@ import qualified Data.Text.Encoding import qualified Data.Text.Lazy-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Data.Text.Lazy.Text Data.Text.Encoding.StrictBuilder where
src/library/LawfulConversions/Relations/LazyTextAndString.hs view
@@ -3,7 +3,7 @@ module LawfulConversions.Relations.LazyTextAndString where import qualified Data.Text.Lazy-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import LawfulConversions.Relations.StringAndText () @@ -12,4 +12,4 @@ maybeFrom = fmap Data.Text.Lazy.fromStrict . maybeFrom instance IsMany String Data.Text.Lazy.Text where- from = fromString+ onfrom = fromString
src/library/LawfulConversions/Relations/LazyTextAndText.hs view
@@ -3,7 +3,7 @@ module LawfulConversions.Relations.LazyTextAndText where import qualified Data.Text.Lazy-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Data.Text.Lazy.Text Text where
− src/library/LawfulConversions/Relations/LazyTextAndUtcTime.hs
@@ -1,15 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.LazyTextAndUtcTime where--import qualified Data.Text.Lazy-import Data.Time-import LawfulConversions.Classes-import LawfulConversions.Prelude-import LawfulConversions.Relations.LazyTextAndString ()-import LawfulConversions.Relations.StringAndUtcTime ()---- | Implements ISO-8601.-instance IsSome Data.Text.Lazy.Text UTCTime where- to = fromString . to- maybeFrom = maybeFrom @String . to
− src/library/LawfulConversions/Relations/LazyTextAndUuid.hs
@@ -1,12 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.LazyTextAndUuid where--import qualified Data.Text.Lazy-import qualified Data.UUID.Types-import LawfulConversions.Classes-import LawfulConversions.Prelude--instance IsSome Data.Text.Lazy.Text UUID where- to = Data.Text.Lazy.fromStrict . Data.UUID.Types.toText- maybeFrom = Data.UUID.Types.fromText . Data.Text.Lazy.toStrict
src/library/LawfulConversions/Relations/LazyTextBuilderAndStrictTextBuilder.hs view
@@ -8,7 +8,7 @@ import qualified Data.Text.Encoding import qualified Data.Text.Lazy import qualified Data.Text.Lazy.Builder-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Data.Text.Lazy.Builder.Builder Data.Text.Encoding.StrictTextBuilder where@@ -30,7 +30,7 @@ import qualified Data.Text.Encoding import qualified Data.Text.Lazy import qualified Data.Text.Lazy.Builder-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Data.Text.Lazy.Builder.Builder Data.Text.Encoding.StrictBuilder where
src/library/LawfulConversions/Relations/LazyTextBuilderAndString.hs view
@@ -4,7 +4,7 @@ import qualified Data.Text.Lazy import qualified Data.Text.Lazy.Builder-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import LawfulConversions.Relations.StringAndText () @@ -13,4 +13,4 @@ maybeFrom = fmap Data.Text.Lazy.Builder.fromText . maybeFrom instance IsMany String Data.Text.Lazy.Builder.Builder where- from = fromString+ onfrom = fromString
src/library/LawfulConversions/Relations/LazyTextBuilderAndText.hs view
@@ -4,7 +4,7 @@ import qualified Data.Text.Lazy import qualified Data.Text.Lazy.Builder-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Data.Text.Lazy.Builder.Builder Text where
− src/library/LawfulConversions/Relations/LazyTextBuilderAndUtcTime.hs
@@ -1,15 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.LazyTextBuilderAndUtcTime where--import qualified Data.Text.Lazy.Builder-import Data.Time-import LawfulConversions.Classes-import LawfulConversions.Prelude-import LawfulConversions.Relations.LazyTextBuilderAndString ()-import LawfulConversions.Relations.StringAndUtcTime ()---- | Implements ISO-8601.-instance IsSome Data.Text.Lazy.Builder.Builder UTCTime where- to = fromString . to- maybeFrom = maybeFrom @String . to
− src/library/LawfulConversions/Relations/LazyTextBuilderAndUuid.hs
@@ -1,13 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.LazyTextBuilderAndUuid where--import qualified Data.Text.Lazy-import qualified Data.Text.Lazy.Builder-import qualified Data.UUID.Types-import LawfulConversions.Classes-import LawfulConversions.Prelude--instance IsSome Data.Text.Lazy.Builder.Builder UUID where- to = Data.Text.Lazy.Builder.fromText . Data.UUID.Types.toText- maybeFrom = Data.UUID.Types.fromText . Data.Text.Lazy.toStrict . Data.Text.Lazy.Builder.toLazyText
src/library/LawfulConversions/Relations/ListAndSeq.hs view
@@ -3,7 +3,7 @@ module LawfulConversions.Relations.ListAndSeq where import qualified Data.Sequence-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome [a] (Seq a) where
src/library/LawfulConversions/Relations/ShortByteStringAndTextArray.hs view
@@ -7,7 +7,7 @@ import qualified Data.ByteString.Short import qualified Data.Text.Array-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import qualified LawfulConversions.TextCompat.Array
src/library/LawfulConversions/Relations/ShortByteStringAndWord8List.hs view
@@ -3,7 +3,7 @@ module LawfulConversions.Relations.ShortByteStringAndWord8List where import qualified Data.ByteString.Short-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import LawfulConversions.Relations.ByteArrayAndShortByteString ()
src/library/LawfulConversions/Relations/StrictTextBuilderAndString.hs view
@@ -6,7 +6,7 @@ #if MIN_VERSION_text(2,1,2) import qualified Data.Text.Encoding-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Relations.StringAndText () import LawfulConversions.Prelude @@ -15,12 +15,12 @@ maybeFrom = fmap Data.Text.Encoding.textToStrictBuilder . maybeFrom instance IsMany String Data.Text.Encoding.StrictTextBuilder where- from = Data.Text.Encoding.textToStrictBuilder . from+ onfrom = Data.Text.Encoding.textToStrictBuilder . onfrom #elif MIN_VERSION_text(2,0,2) import qualified Data.Text.Encoding-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Relations.StringAndText () import LawfulConversions.Prelude @@ -29,6 +29,6 @@ maybeFrom = fmap Data.Text.Encoding.textToStrictBuilder . maybeFrom instance IsMany String Data.Text.Encoding.StrictBuilder where- from = Data.Text.Encoding.textToStrictBuilder . from+ onfrom = Data.Text.Encoding.textToStrictBuilder . onfrom #endif
src/library/LawfulConversions/Relations/StrictTextBuilderAndText.hs view
@@ -6,7 +6,7 @@ #if MIN_VERSION_text(2,1,2) import qualified Data.Text.Encoding-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Text Data.Text.Encoding.StrictTextBuilder where@@ -26,7 +26,7 @@ #elif MIN_VERSION_text(2,0,2) import qualified Data.Text.Encoding-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome Text Data.Text.Encoding.StrictBuilder where
− src/library/LawfulConversions/Relations/StrictTextBuilderAndUtcTime.hs
@@ -1,36 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.StrictTextBuilderAndUtcTime where--#if MIN_VERSION_text(2,1,2)--import qualified Data.Text.Encoding-import Data.Time-import LawfulConversions.Classes-import LawfulConversions.Prelude-import LawfulConversions.Relations.StrictTextBuilderAndString ()-import LawfulConversions.Relations.StringAndText ()-import LawfulConversions.Relations.StringAndUtcTime ()---- | Implements ISO-8601.-instance IsSome Data.Text.Encoding.StrictTextBuilder UTCTime where- to = from . to @String- maybeFrom = maybeFrom @String . to--#elif MIN_VERSION_text(2,0,2)--import qualified Data.Text.Encoding-import Data.Time-import LawfulConversions.Classes-import LawfulConversions.Prelude-import LawfulConversions.Relations.StrictTextBuilderAndString ()-import LawfulConversions.Relations.StringAndText ()-import LawfulConversions.Relations.StringAndUtcTime ()---- | Implements ISO-8601.-instance IsSome Data.Text.Encoding.StrictBuilder UTCTime where- to = from . to @String- maybeFrom = maybeFrom @String . to--#endif
− src/library/LawfulConversions/Relations/StrictTextBuilderAndUuid.hs
@@ -1,28 +0,0 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.StrictTextBuilderAndUuid where--#if MIN_VERSION_text(2,1,2)--import qualified Data.UUID.Types-import qualified Data.Text.Encoding-import LawfulConversions.Classes-import LawfulConversions.Prelude--instance IsSome Data.Text.Encoding.StrictTextBuilder UUID where- to = Data.Text.Encoding.textToStrictBuilder . Data.UUID.Types.toText- maybeFrom = Data.UUID.Types.fromText . Data.Text.Encoding.strictBuilderToText--#elif MIN_VERSION_text(2,0,2)--import qualified Data.UUID.Types-import qualified Data.Text.Encoding-import LawfulConversions.Classes-import LawfulConversions.Prelude--instance IsSome Data.Text.Encoding.StrictBuilder UUID where- to = Data.Text.Encoding.textToStrictBuilder . Data.UUID.Types.toText- maybeFrom = Data.UUID.Types.fromText . Data.Text.Encoding.strictBuilderToText--#endif
src/library/LawfulConversions/Relations/StringAndText.hs view
@@ -3,7 +3,7 @@ module LawfulConversions.Relations.StringAndText where import qualified Data.Text as Text-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude instance IsSome String Text where@@ -16,4 +16,4 @@ else Nothing instance IsMany String Text where- from = Text.pack+ onfrom = Text.pack
− src/library/LawfulConversions/Relations/StringAndUtcTime.hs
@@ -1,13 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.StringAndUtcTime where--import Data.Time-import Data.Time.Format.ISO8601-import LawfulConversions.Classes-import LawfulConversions.Prelude---- | Implements ISO-8601.-instance IsSome String UTCTime where- to = iso8601Show- maybeFrom = iso8601ParseM
− src/library/LawfulConversions/Relations/StringAndUuid.hs
@@ -1,11 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.StringAndUuid where--import qualified Data.UUID.Types-import LawfulConversions.Classes-import LawfulConversions.Prelude--instance IsSome String UUID where- to = Data.UUID.Types.toString- maybeFrom = Data.UUID.Types.fromString
− src/library/LawfulConversions/Relations/TextAndUtcTime.hs
@@ -1,14 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.TextAndUtcTime where--import Data.Time-import LawfulConversions.Classes-import LawfulConversions.Prelude-import LawfulConversions.Relations.StringAndText ()-import LawfulConversions.Relations.StringAndUtcTime ()---- | Implements ISO-8601.-instance IsSome Text UTCTime where- to = fromString . to- maybeFrom = maybeFrom @String . to
− src/library/LawfulConversions/Relations/TextAndUuid.hs
@@ -1,11 +0,0 @@-{-# OPTIONS_GHC -Wno-orphans #-}--module LawfulConversions.Relations.TextAndUuid where--import qualified Data.UUID.Types as Uuid-import LawfulConversions.Classes-import LawfulConversions.Prelude--instance IsSome Text UUID where- to = Uuid.toText- maybeFrom = Uuid.fromText
src/library/LawfulConversions/Relations/TextArrayAndWord8List.hs view
@@ -7,7 +7,7 @@ import qualified Data.ByteString.Short import qualified Data.Text.Array-import LawfulConversions.Classes+import LawfulConversions.Algebra import LawfulConversions.Prelude import qualified LawfulConversions.TextCompat.Array
+ src/library/LawfulConversions/Relations/Void.hs view
@@ -0,0 +1,11 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module LawfulConversions.Relations.Void where++import LawfulConversions.Algebra+import LawfulConversions.Prelude++-- | The empty set has no elements, and therefore is vacuously a subset of any set.+instance IsSome a Void where+ to = absurd+ maybeFrom = const Nothing
src/test/Main.hs view
@@ -110,33 +110,12 @@ testIs @Word64 @Int64 Proxy Proxy, testIs @Word64 @Word64 Proxy Proxy, testIs @Word8 @Int8 Proxy Proxy,- testIs @Word8 @Word8 Proxy Proxy,- testIsSome @Data.Text.Lazy.Text @UTCTime Proxy Proxy,- testIsSome @Data.Text.Lazy.Builder.Builder @UTCTime Proxy Proxy,- testIsSome @String @UTCTime Proxy Proxy,- testIsSome @Text @UTCTime Proxy Proxy,- testIsSome @Data.Text.Lazy.Text @Day Proxy Proxy,- testIsSome @Data.Text.Lazy.Builder.Builder @Day Proxy Proxy,- testIsSome @String @Day Proxy Proxy,- testIsSome @Text @Day Proxy Proxy+ testIs @Word8 @Word8 Proxy Proxy ] testIs :: (Is a b, Eq a, Eq b, Arbitrary a, Show a, Arbitrary b, Show b, Typeable a, Typeable b) => Proxy a -> Proxy b -> TestTree testIs superp subp = isProperties superp subp- & fmap (uncurry testProperty)- & testGroup groupName- where- groupName =- mconcat- [ show (typeOf (asProxyTypeOf undefined superp)),- "/",- show (typeOf (asProxyTypeOf undefined subp))- ]--testIsSome :: (IsSome a b, Eq a, Eq b, Arbitrary a, Show a, Arbitrary b, Show b, Typeable a, Typeable b) => Proxy a -> Proxy b -> TestTree-testIsSome superp subp =- isSomeProperties superp subp & fmap (uncurry testProperty) & testGroup groupName where