| Safe Haskell | Safe-Inferred |
|---|---|
| Language | Haskell2010 |
IsomorphismClass
Contents
Description
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$toa <>tob <>toc
renderNameAndHeight ::Text->Int->TextrenderNameAndHeight name height =from@StrictTextBuilder$ "Height of " <>toname <> " is " <>fromString(show height)
Synopsis
- class IsomorphicTo b a => IsomorphicTo a b where
- to :: b -> a
- from :: IsomorphicTo a b => a -> b
- isomorphicToIso :: (IsomorphicTo a b, Profunctor p, Functor f) => p b (f b) -> p a (f a)
- isomorphicToProperties :: (IsomorphicTo a b, Eq a, Eq b, Arbitrary a, Show a, Arbitrary b, Show b) => Proxy a -> Proxy b -> [(String, Property)]
Typeclasses
class IsomorphicTo b a => IsomorphicTo a b where Source #
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:
- 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.from.to=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.to.from=id
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.
Instances
from :: IsomorphicTo a b => a -> b Source #
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.
Optics
isomorphicToIso :: (IsomorphicTo a b, Profunctor p, Functor f) => p b (f b) -> p a (f a) Source #
Van-Laarhoven-style Isomorphism, compatible with the "lens" library.
Testing
isomorphicToProperties :: (IsomorphicTo a b, Eq a, Eq b, Arbitrary a, Show a, Arbitrary b, Show b) => Proxy a -> Proxy b -> [(String, Property)] Source #
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)