packages feed

isomorphism-class 0.3.0.1 → 0.3.1

raw patch · 7 files changed

+157/−93 lines, 7 filesdep +timePVP ok

version bump matches the API change (PVP)

Dependencies added: time

API changes (from Hackage documentation)

Files

isomorphism-class.cabal view
@@ -1,7 +1,66 @@ cabal-version: 3.0 name: isomorphism-class-version: 0.3.0.1-synopsis: Isomorphism typeclass solving the conversion problem+version: 0.3.1+synopsis: Isomorphism typeclass as a lawful solution to the conversion problem+description:+  = Conversion problem++  How often do you import @Data.Text.Lazy@ only to call @fromStrict@ or @toStrict@?+  How about importing @Data.ByteString.Builder@ only to call its+  'Data.ByteString.Builder.toLazyByteString' and then importing+  @Data.ByteString.Lazy@ only to call its 'Data.ByteString.Lazy.toStrict'?+  How often do you convert from @DiffTime@ to @NominalDiffTime@ and back?++  These are all instances of one pattern. They are conversions between different+  representations of the same information. Codebases that don't attempt to+  abstract over this pattern tend to be sprawling with this type of+  boilerplate. It's noise to the code reader, it's a burden to implementors+  and maintainers.++  = Why another conversion library?++  Many libraries exist that approach the conversion problem. However, most of+  them provide lawless typeclasses, leaving it up to the author of the+  instance to define what makes a proper conversion. This results in+  inconsistencies across instances, their behavior not being evident to+  the user and no way to check whether an instance is correct.++  This library tackles this problem with a lawful typeclass, making it+  evident what any of its instances do, and it provides a property-test for you+  to validate your instances.++  = The insight++  The key insight of this library is that if you add a requirement for the+  conversion to be lossless and to have a mirror conversion in the opposite+  direction, there usually appears to be only one way of defining it. That+  makes it very clear what the conversion does to the user and how to define+  it for the author of the conversion.+  It also gives clear criteria for validating whether the instances are correct, which can be encoded in property-tests.++  That insight itself stems from an observation that almost all of the+  practical conversions in Haskell share a property: you can restore the+  original data from its converted form. E.g., you can get a text from+  a text-builder and you can create a text-builder from a text, you can convert+  a bytestring into a list of bytes and vice-versa, bytestring to\/from bytearray,+  strict bytestring to\/from lazy, list to\/from sequence, sequence to/from+  vector, set of ints to\/from int-set. In other words, it's always a two-way+  street with them and there are many instances of this pattern.++  A few other accidental findings like encoding this property with recursive+  typeclass constraints and fine-tuning for the use of+  the @TypeApplications@ extension resulted in a terse and clear API.++  = Other work and acknowledgements++  There is ["lawful-conversions"](https://hackage.haskell.org/package/lawful-conversions), which is a sibling of this library expanding upon the ideas from this one to also cover the patterns of smart construction and canonicalization. It's more involved and has different tradeoffs. Both libraries are maintained, letting their designs compete.++  Some ideas and concepts are also shared with the following libraries:++  - [control-iso](https://hackage.haskell.org/package/control-iso)+  - [type-iso](https://hackage.haskell.org/package/type-iso)+  - [injections](https://hackage.haskell.org/package/injections)+ category: Conversion homepage: https://github.com/nikita-volkov/isomorphism-class bug-reports: https://github.com/nikita-volkov/isomorphism-class/issues@@ -10,12 +69,12 @@ copyright: (c) 2022 Nikita Volkov license: MIT license-file: LICENSE-extra-source-files:+extra-doc-files:   CHANGELOG.md  source-repository head   type: git-  location: git://github.com/nikita-volkov/isomorphism-class.git+  location: https://github.com/nikita-volkov/isomorphism-class  common language-settings   default-language: Haskell2010@@ -55,6 +114,8 @@     IsomorphismClass.Relations.ByteStringAndShortByteString     IsomorphismClass.Relations.ByteStringAndTextArray     IsomorphismClass.Relations.ByteStringAndWord8List+    IsomorphismClass.Relations.DiffTimeAndNominalDiffTime+    IsomorphismClass.Relations.DiffTimeAndPico     IsomorphismClass.Relations.Int16AndWord16     IsomorphismClass.Relations.Int32AndWord32     IsomorphismClass.Relations.Int64AndWord64@@ -75,6 +136,7 @@     IsomorphismClass.Relations.LazyTextBuilderAndStrictTextBuilder     IsomorphismClass.Relations.LazyTextBuilderAndText     IsomorphismClass.Relations.ListAndSeq+    IsomorphismClass.Relations.NominalDiffTimeAndPico     IsomorphismClass.Relations.ShortByteStringAndTextArray     IsomorphismClass.Relations.ShortByteStringAndWord8List     IsomorphismClass.Relations.StrictTextBuilderAndText@@ -90,6 +152,7 @@     primitive >=0.7 && <0.10,     profunctors >=5 && <6,     text >=1.2 && <2.2,+    time >=1.9 && <2,     unordered-containers >=0.2 && <0.3,     vector >=0.12 && <0.14, 
library/IsomorphismClass.hs view
@@ -1,55 +1,5 @@ -- |--- Lawful solution to the conversion problem.------ = Conversion problem------ Have you ever looked for a @toString@ function? How often do you--- import @Data.Text.Lazy@ only to call its 'Data.Text.Lazy.fromStrict'? How--- about importing @Data.ByteString.Builder@ only to call its--- 'Data.ByteString.Builder.toLazyByteString' and then importing--- @Data.ByteString.Lazy@ only to call its 'Data.ByteString.Lazy.toStrict'?------ Those all are instances of one pattern. They are conversions between--- representations of the same information. Codebases that don't attempt to--- abstract over this pattern tend to be sprawling with this type of--- boilerplate. It's noise to the codereader, it's a burden to the--- implementor and the maintainer.------ = Why another conversion library?------ Many libraries exist that approach the conversion problem. However most of--- them provide lawless typeclasses leaving it up to the author of the--- instance to define what makes a proper conversion. This results in--- inconsistencies across instances, their behaviour not being evident to--- the user and no way to check whether an instance is correct.------ This library tackles this problem with a lawful typeclass, making it--- evident what any of its instances do and it provides a property-test for you--- to validate your instances.------ = The laws------ The key insight of this library is that if you add a requirement for the--- conversion to be lossless and to have a mirror conversion in the opposite--- direction, there usually appears to be only one way of defining it. That--- makes it very clear what the conversion does to the user and how to define--- it to the author of the conversion.--- It also gives a clear criteria for validating whether the instances are correct, which can be encoded in property-tests.------ That insight itself stems from an observation that almost all of the--- practical conversions in Haskell share a property: you can restore the--- original data from its converted form. E.g., you can get a text from--- a text-builder and you can create a text-builder from a text, you can convert--- a bytestring into a list of bytes and vice-versa, bytestring to\/from bytearray,--- strict bytestring to\/from lazy, list to\/from sequence, sequence to/from--- vector, set of ints to\/from int-set. In other words, it's always a two-way--- street with them and there's a lot of instances of this pattern.--- -- = UX------ A few other accidental findings like encoding this property with recursive--- typeclass constraints and fine-tuning for the use of--- the @TypeApplications@ extension resulted in a terse and clear API. -- -- Essentially the whole API is just two functions: 'to' and 'from'. Both -- perform a conversion between two types. The only difference between them
library/IsomorphismClass/Relations.hs view
@@ -1,39 +1,42 @@-module IsomorphismClass.Relations (module Exports) where+module IsomorphismClass.Relations () where -import IsomorphismClass.Relations.BoxedVectorAndList as Exports-import IsomorphismClass.Relations.BoxedVectorAndSeq as Exports-import IsomorphismClass.Relations.ByteArrayAndByteString as Exports-import IsomorphismClass.Relations.ByteArrayAndLazyByteString as Exports-import IsomorphismClass.Relations.ByteArrayAndLazyByteStringBuilder as Exports-import IsomorphismClass.Relations.ByteArrayAndShortByteString as Exports-import IsomorphismClass.Relations.ByteArrayAndTextArray as Exports-import IsomorphismClass.Relations.ByteArrayAndWord8List as Exports-import IsomorphismClass.Relations.ByteStringAndLazyByteString as Exports-import IsomorphismClass.Relations.ByteStringAndLazyByteStringBuilder as Exports-import IsomorphismClass.Relations.ByteStringAndShortByteString as Exports-import IsomorphismClass.Relations.ByteStringAndTextArray as Exports-import IsomorphismClass.Relations.ByteStringAndWord8List as Exports-import IsomorphismClass.Relations.Int16AndWord16 as Exports-import IsomorphismClass.Relations.Int32AndWord32 as Exports-import IsomorphismClass.Relations.Int64AndWord64 as Exports-import IsomorphismClass.Relations.Int8AndWord8 as Exports-import IsomorphismClass.Relations.IntAndWord as Exports-import IsomorphismClass.Relations.IntMapAndMapOfInt as Exports-import IsomorphismClass.Relations.IntSetAndSetOfInt as Exports-import IsomorphismClass.Relations.LazyByteStringAndLazyByteStringBuilder as Exports-import IsomorphismClass.Relations.LazyByteStringAndShortByteString as Exports-import IsomorphismClass.Relations.LazyByteStringAndTextArray as Exports-import IsomorphismClass.Relations.LazyByteStringAndWord8List as Exports-import IsomorphismClass.Relations.LazyByteStringBuilderAndShortByteString as Exports-import IsomorphismClass.Relations.LazyByteStringBuilderAndTextArray as Exports-import IsomorphismClass.Relations.LazyByteStringBuilderAndWord8List as Exports-import IsomorphismClass.Relations.LazyTextAndLazyTextBuilder as Exports-import IsomorphismClass.Relations.LazyTextAndStrictTextBuilder as Exports-import IsomorphismClass.Relations.LazyTextAndText as Exports-import IsomorphismClass.Relations.LazyTextBuilderAndStrictTextBuilder as Exports-import IsomorphismClass.Relations.LazyTextBuilderAndText as Exports-import IsomorphismClass.Relations.ListAndSeq as Exports-import IsomorphismClass.Relations.ShortByteStringAndTextArray as Exports-import IsomorphismClass.Relations.ShortByteStringAndWord8List as Exports-import IsomorphismClass.Relations.StrictTextBuilderAndText as Exports-import IsomorphismClass.Relations.TextArrayAndWord8List as Exports+import IsomorphismClass.Relations.BoxedVectorAndList ()+import IsomorphismClass.Relations.BoxedVectorAndSeq ()+import IsomorphismClass.Relations.ByteArrayAndByteString ()+import IsomorphismClass.Relations.ByteArrayAndLazyByteString ()+import IsomorphismClass.Relations.ByteArrayAndLazyByteStringBuilder ()+import IsomorphismClass.Relations.ByteArrayAndShortByteString ()+import IsomorphismClass.Relations.ByteArrayAndTextArray ()+import IsomorphismClass.Relations.ByteArrayAndWord8List ()+import IsomorphismClass.Relations.ByteStringAndLazyByteString ()+import IsomorphismClass.Relations.ByteStringAndLazyByteStringBuilder ()+import IsomorphismClass.Relations.ByteStringAndShortByteString ()+import IsomorphismClass.Relations.ByteStringAndTextArray ()+import IsomorphismClass.Relations.ByteStringAndWord8List ()+import IsomorphismClass.Relations.DiffTimeAndNominalDiffTime ()+import IsomorphismClass.Relations.DiffTimeAndPico ()+import IsomorphismClass.Relations.Int16AndWord16 ()+import IsomorphismClass.Relations.Int32AndWord32 ()+import IsomorphismClass.Relations.Int64AndWord64 ()+import IsomorphismClass.Relations.Int8AndWord8 ()+import IsomorphismClass.Relations.IntAndWord ()+import IsomorphismClass.Relations.IntMapAndMapOfInt ()+import IsomorphismClass.Relations.IntSetAndSetOfInt ()+import IsomorphismClass.Relations.LazyByteStringAndLazyByteStringBuilder ()+import IsomorphismClass.Relations.LazyByteStringAndShortByteString ()+import IsomorphismClass.Relations.LazyByteStringAndTextArray ()+import IsomorphismClass.Relations.LazyByteStringAndWord8List ()+import IsomorphismClass.Relations.LazyByteStringBuilderAndShortByteString ()+import IsomorphismClass.Relations.LazyByteStringBuilderAndTextArray ()+import IsomorphismClass.Relations.LazyByteStringBuilderAndWord8List ()+import IsomorphismClass.Relations.LazyTextAndLazyTextBuilder ()+import IsomorphismClass.Relations.LazyTextAndStrictTextBuilder ()+import IsomorphismClass.Relations.LazyTextAndText ()+import IsomorphismClass.Relations.LazyTextBuilderAndStrictTextBuilder ()+import IsomorphismClass.Relations.LazyTextBuilderAndText ()+import IsomorphismClass.Relations.ListAndSeq ()+import IsomorphismClass.Relations.NominalDiffTimeAndPico ()+import IsomorphismClass.Relations.ShortByteStringAndTextArray ()+import IsomorphismClass.Relations.ShortByteStringAndWord8List ()+import IsomorphismClass.Relations.StrictTextBuilderAndText ()+import IsomorphismClass.Relations.TextArrayAndWord8List ()
+ library/IsomorphismClass/Relations/DiffTimeAndNominalDiffTime.hs view
@@ -0,0 +1,16 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module IsomorphismClass.Relations.DiffTimeAndNominalDiffTime where++import Data.Time+import IsomorphismClass.Classes+import IsomorphismClass.Prelude++instance IsomorphicTo DiffTime NominalDiffTime where+  to = picosecondsToDiffTime . picoToInteger . nominalDiffTimeToSeconds+    where+      picoToInteger :: Pico -> Integer+      picoToInteger (MkFixed p) = p++instance IsomorphicTo NominalDiffTime DiffTime where+  to = secondsToNominalDiffTime . MkFixed . diffTimeToPicoseconds
+ library/IsomorphismClass/Relations/DiffTimeAndPico.hs view
@@ -0,0 +1,16 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module IsomorphismClass.Relations.DiffTimeAndPico where++import Data.Time+import IsomorphismClass.Classes+import IsomorphismClass.Prelude++instance IsomorphicTo DiffTime Pico where+  to = picosecondsToDiffTime . picoToInteger+    where+      picoToInteger :: Pico -> Integer+      picoToInteger (MkFixed p) = p++instance IsomorphicTo Pico DiffTime where+  to = MkFixed . diffTimeToPicoseconds
+ library/IsomorphismClass/Relations/NominalDiffTimeAndPico.hs view
@@ -0,0 +1,13 @@+{-# OPTIONS_GHC -Wno-orphans #-}++module IsomorphismClass.Relations.NominalDiffTimeAndPico where++import Data.Time+import IsomorphismClass.Classes+import IsomorphismClass.Prelude++instance IsomorphicTo NominalDiffTime Pico where+  to = secondsToNominalDiffTime++instance IsomorphicTo Pico NominalDiffTime where+  to = nominalDiffTimeToSeconds
test/Main.hs view
@@ -110,7 +110,10 @@       testPair @Word64 @Int64 Proxy Proxy,       testPair @Word64 @Word64 Proxy Proxy,       testPair @Word8 @Int8 Proxy Proxy,-      testPair @Word8 @Word8 Proxy Proxy+      testPair @Word8 @Word8 Proxy Proxy,+      testPair @DiffTime @NominalDiffTime Proxy Proxy,+      testPair @DiffTime @Pico Proxy Proxy,+      testPair @NominalDiffTime @Pico Proxy Proxy     ]  testPair :: (IsomorphicTo a b, Eq a, Eq b, Arbitrary a, Show a, Arbitrary b, Show b, Typeable a, Typeable b) => Proxy a -> Proxy b -> TestTree