Open ferranpujolcamins opened 4 years ago
@truizlop let me know what you think
I am glad that you are taking this further. What you are describing here is what I started in the BowGenerics module, but is incomplete. NaturallyIsomorphic
would roughly correspond to the protocol Generic
. The module also includes HList
to avoid nested PairK
when there are multiple components in a product. Likewise, we have Coproduct
for multiple arities. You may want to check that out.
I would include your proposal in the BowGenerics module, except maybe the PairK
which, as EitherK
, can be in the main Bow module.
Oh, I didn't realise the Generic module!
Certainly, in my proposal n-products and coproducts are not supported very well, specially from the point of view of a user writing an ADT. Also, Generic allows a type to be isomorphic to any number of types, while my NaturallyIsomorphic forces you to choose one.
Do you have an example of a data type defined with the Generic module?
NaturallyIsomorphic
vs Generic
Generic
protocol is kind of a multi-parameter type class, but since Swift does not support that, in order for a type to "inherit" methods from its Repr
, we'll need to always pass around a value of Generic, a witness of the isomorphism.
This is bad, because it's a lot of boilerplate, but it's good, because you can choose what isomorphic type you "inherit" each method from. So for example, you can "inherit" Codable
methods from an isomorphic enum while inheriting Functor
methods from EitherK
.
With NaturallyIsomorphic
, you can just call the inherited methods on your type, but you are forced to choose a single isomorphic type. However, you can always use a new type wrapper to inherit from another isomorphic type.
So, in both cases, you need some boilerplate when there's more than one isomorphic types. However, with NaturallyIsomorphic
there's no boilerplate involved when there's only one isomorphic type, as opposed to Generic
.
So, from that point of view, I think the approach of NaturallyIsomorphic
is preferable.
Nested PairK
s or EitherK
s
This is something we can polish after everything else. It's a nice to have. So I'll study how to port HList, or how to merge both ideas later.
Abstract
In this issue I present a way to automatically "derive" instances of typeclasses for any algebraic data types.
Description
We need a new
NaturallyIsomorphic
typeclass (protocol) for higher-kinded types:Higher-kinded types conforming to
NaturallyIsomorphic
can get instances of typeclasses from the type they areIsomorphicTo
[1]. For example, if a type isNaturallyIsomorphic
to aFunctor
then it is also aFunctor
.We then need to realize that any algebraic data type is isomorphic to a canonical algebraic data type formed by nested
EitherK
s andPairK
s (PairK
is the obvious product type counterpart ofEitherK
[2]).Then, we can automatically get an instance for any typeclass (that has an instance for
EitherK
andPairK
) by only making our typeNaturallyIsomorphic
to some nesting ofEitherK
s andPairK
s. We'll see an example of this equivalence below.Sample usage
Here we define a non-trivial algebraic data type
ADT
. We define it directly with nestedEitherK
s andPairK
s, so the implementation ofNaturallyIsomorphic
is trivial.If we want, we can always define smart constructors or computed properties to hide the inner nesting of
EitherK
s andPairK
s.Note how we don't need to provide implementations for
EquatableK
andFunctor
.Passing test:
Potential implementation
[1]
NaturallyIsomorphic
"inherits" instances of typeclasses from itsIsomorphicTo
associated type.[2]
PairK
Modules
Bow
Breaking changes
None, new additions.
Drawbacks
I haven't tested, but I assume the performance is worse than manually written typeclass instances. Despite this, I believe the technique presented here is valuable because:
Proposed roadmap
PairK
implementation and testsNaturallyIsomorphic
implementation and testsOpen questions