-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/

-- | Isomorphism typeclass as a lawful solution to the conversion problem
--   
--   
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
--   toLazyByteString and then importing
--   Data.ByteString.Lazy only to call its toStrict? How
--   often do you convert from DiffTime to
--   NominalDiffTime or 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
--   
--   
--   
- lawful-conversions - sibling of this library expanding upon
--   the same insights 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
--   
- type-iso
--   
- injections
--   
@package isomorphism-class
@version 0.3.1.2

-- | 
UX
--   
--   Essentially the whole API is just two functions: to and
--   from. Both perform a conversion between two types. The only
--   difference between them is in what the first type application
--   parameter specifies. E.g.:
--   
--   
--   toText = to @Text
--   
--   
--   
--   fromBuilder = from @Builder
--   
--   
--   The types are self-evident:
--   
--   
--   > :t to @Text
--   to @Text :: IsomorphicTo Text b => b -> Text
--   
--   
--   
--   > :t from @Builder
--   from @Builder :: IsomorphicTo Builder b => Builder -> b
--   
--   
--   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 inferencer or the reader.
--   
--   
Examples
--   
--   
--   combineEncodings :: ShortByteString -> ByteArray -> ByteString -> [Word8]
--   combineEncodings a b c =
--     from @Builder $
--       to a <> to b <> to c
--   
--   
--   Which is equivalent to:
--   
--   
--   combineEncodings :: ShortByteString -> ByteArray -> ByteString -> [Word8]
--   combineEncodings a b c =
--     LazyByteString.unpack $
--       Builder.toLazyByteString $
--         mconcat
--           [ Builder.shortByteString a,
--             Builder.shortByteString
--               ( let ByteArray.ByteArray array = b
--                  in ShortByteString.SBS array
--               ),
--             Builder.lazyByteString c
--           ]
--   
module IsomorphismClass

-- | 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 IsomorphicTo a b as "B is
--   isomorphic to A".
--   
--   
Laws
--   
--   B is isomorphic to A if and only if there exists a
--   conversion from B to A (to) and a conversion from
--   A to B (from) such that:
--   
--   
--   
- from . to = id - For all values of
--   B converting from B to A and then converting from
--   A to B produces a value that is identical to the
--   original.
--   
- to . from = id - For all values of
--   A converting from A to B and then converting from
--   B to A produces a value that is identical to the
--   original.
--   
--   
--   
Testing
--   
--   For testing whether your instances conform to these laws use
--   isomorphicToProperties.
--   
--   
Instance Definition
--   
--   For each pair of isomorphic types (A and B) the compiler
--   will require you to define two instances, namely: IsomorphicTo A
--   B and IsomorphicTo B A.
class IsomorphicTo b a => IsomorphicTo a b

-- | Convert a value into an isomophic type.
to :: IsomorphicTo a b => b -> a

-- | to in reverse direction.
--   
--   Particularly useful in combination with the TypeApplications
--   extension, where it allows to specify the input type, e.g.:
--   
--   
--   fromText :: IsomorphicTo Text b => Text -> b
--   fromText = from @Text
--   
--   
--   The first type application of the to function on the other hand
--   specifies the output data type.
from :: IsomorphicTo a b => a -> b

-- | Van-Laarhoven-style Isomorphism, compatible with the "lens" library.
isomorphicToIso :: (IsomorphicTo a b, Profunctor p, Functor f) => p b (f b) -> p a (f a)

-- | Properties testing whether an instance satisfies the laws of
--   IsomorphicTo.
--   
--   The instance is identified via the proxy types that you provide.
--   
--   E.g., here's how you can integrate it into an Hspec test-suite:
--   
--   
--   spec = do
--     describe "IsomorphicTo laws" do
--       traverse_
--         (uncurry prop)
--         (isomorphicToProperties @Int32 @Word32 Proxy Proxy)
--   
isomorphicToProperties :: (IsomorphicTo a b, Eq a, Eq b, Arbitrary a, Show a, Arbitrary b, Show b) => Proxy a -> Proxy b -> [(String, Property)]
