module LawfulConversions.Classes.Is ( module LawfulConversions.Classes.Is, module LawfulConversions.Classes.IsMany, ) where import LawfulConversions.Classes.IsMany -- | 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