Yes, I agree .
I think maybe the most sense would make to brush up fun_land
to make sure it actually implements the ADT-hierarchy properly (which it already does, but there are some omissions) and most importantly: it becoming more clear in its usage.
It should be very friendly to use. (And maybe it needs a better name?)
The idea is to both create a set of behaviours that allows implementing the different ADT typeclasses, as well as a clear public API that internally dispatches on them, allowing functions like take_while
, split
, etc. to work on anything that implements the correct behaviours.
(Behaviours are used for two reasons over protocols here:
- The functions that are part of the behaviour also become part of the public API of the implementor’s module. So
Mappable.map(%Queue{}, fun)
will dispatch toQueue.map(%Queue{}, fun)
, but the latter is also directly visible and introspectable. - It is possible to create default implementations for many operations if the data types implement a higher typeclass: For instance,
map
can be built out ofpure
andapply
. I’d like to specify these asdefoverridable
to give programmers the flexibility to still implement them themselves (for e.g. extra speed). AFAIK, usingdefoverridable
is impossible with protocols.
)
On the other hand, there are also multiple data structures that could be built on top of different practical implementations. An example: A binary tree could both be built as nested maps/tuples, or instead on top of an array (which could be built on top of a numerical-indexed map). It therefore makes sense to create a unified interface for these data types as well, and separate their external interface from their internal workings. Main drawback here might be performance, however.