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


-- | Lawful typeclasses for bidirectional conversion between types
--   
--   <h1>Summary</h1>
--   
--   Lawful typeclasses capturing three patterns of bidirectional mapping
--   and forming a layered hierarchy with an ascending strictness of laws.
--   
--   <ol>
--   <li>Smart constructor</li>
--   <li>Canonicalization or lossy conversion</li>
--   <li>Isomorphism or lossless conversion</li>
--   </ol>
--   
--   <h1>The conversion problem</h1>
--   
--   Have you ever looked for a <tt>toString</tt> function? How often do
--   you import <tt>Data.Text.Lazy</tt> only to call its
--   <tt>fromStrict</tt>? How about importing
--   <tt>Data.ByteString.Builder</tt> only to call its
--   <tt>toLazyByteString</tt> and then importing
--   <tt>Data.ByteString.Lazy</tt> only to call its <tt>toStrict</tt>?
--   
--   Those all are 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 codereader, it's a burden
--   to the implementor and the maintainer.
--   
--   <h1>Why another conversion library?</h1>
--   
--   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 hierarchy,
--   making it evident what any of its instances do and it provides
--   property-tests for you to validate your instances.
--   
--   <h1>Prior work and acknowledgements</h1>
--   
--   This library is a direct successor of the "<a>isomorphism-class</a>"
--   library, expanding upon the patterns discovered there. It also shares
--   some ideas with "<a>control-iso</a>" and "<a>type-iso</a>".
@package lawful-conversions
@version 0.1.6


-- | <h1>Conversions</h1>
--   
--   The main part of the API is two functions: <a>to</a> and <a>from</a>.
--   Both perform a conversion between two types. The main difference
--   between them is in what the first type application parameter
--   specifies. E.g.:
--   
--   <pre>
--   toString = to @String
--   </pre>
--   
--   <pre>
--   fromText = from @Text
--   </pre>
--   
--   The types should be self-evident:
--   
--   <pre>
--   &gt; :t to @String
--   to @String :: IsSome String b =&gt; b -&gt; String
--   </pre>
--   
--   <pre>
--   &gt; :t from @Text
--   from @Text :: IsMany Text b =&gt; Text -&gt; b
--   </pre>
--   
--   In other words <a>to</a> and <a>from</a> 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.
--   
--   <h2>Examples</h2>
--   
--   <pre>
--   combineEncodings :: <a>ShortByteString</a> -&gt; <a>ByteArray</a> -&gt; [<tt>Word8</tt>] -&gt; <a>ByteString</a>
--   combineEncodings a b c =
--     <a>from</a> @<a>Builder</a> $
--       <a>to</a> a &lt;&gt; <a>to</a> b &lt;&gt; <a>to</a> c
--   </pre>
--   
--   <pre>
--   renderNameAndHeight :: <tt>Text</tt> -&gt; <tt>Int</tt> -&gt; <tt>Text</tt>
--   renderNameAndHeight name height =
--     <a>from</a> @<a>StrictTextBuilder</a> $
--       "Height of " &lt;&gt; <a>from</a> name &lt;&gt; " is " &lt;&gt; <a>from</a> (show height)
--   </pre>
--   
--   <h1>Partial conversions</h1>
--   
--   This library also captures the pattern of smart constructors via the
--   <a>IsSome</a> class, which associates a total <a>to</a> conversion
--   with its partial inverse <a>maybeFrom</a>.
--   
--   This captures the codec relationship between types. E.g.,
--   
--   <ul>
--   <li>Every <tt>Int16</tt> can be losslessly converted into
--   <tt>Int32</tt>, but not every <tt>Int32</tt> can be losslessly
--   converted into <tt>Int16</tt>.</li>
--   <li>Every <tt>Text</tt> can be converted into <tt>ByteString</tt> via
--   UTF-8 encoding, but not every <tt>ByteString</tt> forms a valid UTF-8
--   sequence.</li>
--   <li>Every URL can be uniquely represented as <tt>Text</tt>, but most
--   <tt>Text</tt>s are not URLs unfortunately.</li>
--   <li>UTCTime, JSON, Email, etc.</li>
--   </ul>
--   
--   <h2>Examples</h2>
--   
--   Here's an example of implementing the Smart Constructor pattern.
--   
--   <pre>
--   module Percent (Percent) where
--   
--   import LawfulConversions
--   
--   newtype Percent = Percent Double
--   
--   instance IsSome Double Percent where
--     to (Percent double) = double
--     maybeFrom double =
--       if double &lt; 0 || double &gt; 1
--         then Nothing
--         else Just (Percent double)
--   </pre>
--   
--   You can also expand upon that and provide a default handling of
--   invalid values effectively providing a lossy canonicalizing conversion
--   (<a>Surjection</a>):
--   
--   <pre>
--   instance IsMany Double Percent where
--     from double =
--       if double &lt; 0
--         then Percent 0
--         else if double &gt; 1
--           then Percent 1
--           else Percent double
--   </pre>
--   
--   However declaring an instance of <a>Is</a> would be incorrect, because
--   this conversion is partial. Namely, while every <tt>Percent</tt> value
--   can be losslessly transformed into <tt>Double</tt>, not every
--   <tt>Double</tt> can be losslessly transformed into <tt>Percent</tt>.
module LawfulConversions

-- | Evidence that all values of type <tt>b</tt> form a subset of all
--   values of type <tt>a</tt>.
--   
--   <a>From Wikipedia</a>:
--   
--   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.
--   
--   <h3>Laws</h3>
--   
--   <h4><a>to</a> is <a>injective</a></h4>
--   
--   For every two values of type <tt>b</tt> that are not equal converting
--   with <a>to</a> produces values that are not equal as well:
--   
--   <pre>
--   \(b1, b2) -&gt; b1 == b2 || to @a b1 /= to @a b2
--   </pre>
--   
--   <h4><a>maybeFrom</a> is a <a>partial inverse</a> of <a>to</a></h4>
--   
--   For all values of <tt>b</tt> converting to <tt>a</tt> and then
--   attempting to convert back to <tt>b</tt> always succeeds and produces
--   a value that is equal to the original:
--   
--   <pre>
--   \b -&gt; maybeFrom (to @a b) == Just b
--   </pre>
--   
--   <h3>Testing</h3>
--   
--   For testing whether your instances conform to these laws use
--   <a>isSomeProperties</a>.
class IsSome a b

-- | Convert a value of a subset type to a superset type.
to :: IsSome a b => b -> a

-- | <a>Partial inverse</a> of <a>to</a>.
maybeFrom :: IsSome a b => a -> Maybe b

-- | Requires the presence of <a>IsSome</a> in reverse direction.
($dmmaybeFrom) :: (IsSome a b, IsSome b a) => a -> Maybe b

-- | Lossy or canonicalizing conversion. Captures mappings from multiple
--   alternative inputs into one output.
--   
--   E.g.,
--   
--   <ul>
--   <li><tt>ByteString</tt> can be decoded into <tt>Text</tt> with UTF-8
--   leniently, replacing the invalid chars with a default char.</li>
--   <li><tt>String</tt> has a wider range of supported chars than
--   <tt>Text</tt>, so some chars get replaced too.</li>
--   </ul>
--   
--   <h3>Laws</h3>
--   
--   <h4><a>from</a> is an <a>inverse</a> of <a>to</a></h4>
--   
--   <pre>
--   \b -&gt; b == from (to @a b)
--   </pre>
--   
--   <h3>Testing</h3>
--   
--   For testing whether your instances conform to these laws use
--   <a>isManyProperties</a>.
class IsSome a b => IsMany a b

-- | Possibly lossy inverse of <a>to</a>. <a>Surjection</a> from <tt>a</tt>
--   to <tt>b</tt>.
--   
--   Particularly useful in combination with the <tt>TypeApplications</tt>
--   extension, where it allows to specify the input type, e.g.:
--   
--   <pre>
--   fromText :: IsMany Text b =&gt; Text -&gt; b
--   fromText = from @Text
--   </pre>
--   
--   The first type application of the <a>to</a> function on the other hand
--   specifies the output data type.
from :: IsMany a b => a -> b

-- | Requires the presence of <a>IsSome</a> in reverse direction.
($dmfrom) :: (IsMany a b, IsSome b a) => a -> b

-- | 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 <tt>Is a b</tt> as "<i>B</i> is <i>A</i>".
--   
--   <h3>Laws</h3>
--   
--   <h4><a>from</a> is an <a>inverse</a> of <a>to</a></h4>
--   
--   For all values of <i>b</i> converting from <i>b</i> to <i>a</i> and
--   then converting from <i>a</i> to <i>b</i> produces the original value:
--   
--   <pre>
--   \b -&gt; b == from (to @a b)
--   </pre>
--   
--   <h4><a>to</a> is an <a>inverse</a> of <a>from</a></h4>
--   
--   For all values of <i>a</i> converting from <i>a</i> to <i>b</i> and
--   then converting from <i>b</i> to <i>a</i> produces the original value:
--   
--   <pre>
--   \a -&gt; a == to (from @a @b a)
--   </pre>
--   
--   <h3>Testing</h3>
--   
--   For testing whether your instances conform to these laws use
--   <a>isProperties</a>.
--   
--   <h3>Instance Definition</h3>
--   
--   For each pair of isomorphic types (<i>A</i> and <i>B</i>) the compiler
--   will require you to define six instances, namely: <tt>Is A B</tt> and
--   <tt>Is B A</tt>, <tt>IsMany A B</tt> and <tt>IsMany B A</tt>,
--   <tt>IsSome A B</tt> and <tt>IsSome B A</tt>.
--   
--   Instances of <tt>Is</tt> do not define any functions and serve merely
--   as a statement that the laws are satisfied.
--   
--   <h4>Example: Lazy Text and Text</h4>
--   
--   <pre>
--   instance IsSome <a>Data.Text.Lazy.LazyText</a> <a>Data.Text.Text</a> where
--     to = LazyText.<a>fromStrict</a>
--   
--   instance IsSome <a>Data.Text.Text</a> <a>Data.Text.Lazy.LazyText</a> where
--     to = LazyText.<a>toStrict</a>
--   
--   instance IsMany <a>Data.Text.Lazy.LazyText</a> <a>Data.Text.Text</a>
--   
--   instance IsMany <a>Data.Text.Text</a> <a>Data.Text.Lazy.LazyText</a>
--   
--   instance Is <a>Data.Text.Lazy.LazyText</a> <a>Data.Text.Text</a>
--   
--   instance Is <a>Data.Text.Text</a> <a>Data.Text.Lazy.LazyText</a>
--   </pre>
class (IsMany a b, Is b a) => Is a b

-- | Van-Laarhoven-style Prism, compatible with libraries like "lens" and
--   "optics".
isSomePrism :: (IsSome a b, Choice p, Applicative f) => p b (f b) -> p a (f a)

-- | 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)

-- | 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)

-- | Helper for deriving common instances on types which have an instance
--   of <tt><a>IsSome</a> a</tt> using the <tt>DerivingVia</tt> extension.
--   
--   E.g.,
--   
--   <pre>
--   newtype Percent = Percent Double
--     deriving newtype (Show, Eq, Ord)
--     deriving (Read, Arbitrary) via (ViaIsSome Double Percent)
--   
--   instance IsSome Double Percent where
--     to (Percent double) = double
--     maybeFrom double =
--       if double &lt; 0 || double &gt; 1
--         then Nothing
--         else Just (Percent double)
--   </pre>
--   
--   In the code above all the instances that are able to construct the
--   values of <tt>Percent</tt> are automatically derived based on the
--   <tt>IsSome Double Percent</tt> instance. This guarantees that they
--   only construct values that pass thru the checks defined in
--   <a>maybeFrom</a>.
newtype ViaIsSome a b
ViaIsSome :: b -> ViaIsSome a b

-- | Properties testing whether an instance satisfies the laws of
--   <a>IsSome</a>.
--   
--   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:
--   
--   <pre>
--   spec = do
--     describe "IsSome laws" do
--       traverse_
--         (uncurry prop)
--         (isSomeProperties @Int32 @Int16 Proxy Proxy)
--   </pre>
isSomeProperties :: (IsSome a b, Eq a, Eq b, Show a, Show b, Arbitrary b) => Proxy a -> Proxy b -> [(String, Property)]

-- | Properties testing whether an instance satisfies the laws of
--   <a>IsMany</a>.
--   
--   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:
--   
--   <pre>
--   spec = do
--     describe "IsMany laws" do
--       traverse_
--         (uncurry prop)
--         (isManyProperties @String @Text Proxy Proxy)
--   </pre>
isManyProperties :: (IsMany a b, Eq a, Eq b, Show a, Show b, Arbitrary b) => Proxy a -> Proxy b -> [(String, Property)]

-- | Properties testing whether an instance satisfies the laws of
--   <a>Is</a>.
--   
--   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:
--   
--   <pre>
--   spec = do
--     describe "Is laws" do
--       traverse_
--         (uncurry prop)
--         (isProperties @Int32 @Word32 Proxy Proxy)
--   </pre>
isProperties :: (Is a b, Eq a, Eq b, Show a, Show b, Arbitrary a, Arbitrary b) => Proxy a -> Proxy b -> [(String, Property)]
