    module IsomorphismClass.Classes.IsomorphicTo where

    import IsomorphismClass.Prelude

    -- | 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 'IsomorphismClass.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 where
      -- |
      -- Convert a value into an isomophic type.
      to :: b -> a

    -- | Every type is isomorphic to itself.
    instance IsomorphicTo a a where
      to :: a -> a
    to = a -> a
    forall a. a -> a
    forall {k} (cat :: k -> k -> *) (a :: k). Category cat => cat a a
    id

    -- |
    -- '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
    from :: forall a b. IsomorphicTo a b => a -> b
    from = a -> b
    forall a b. IsomorphicTo a b => b -> a
    to