crocks icon indicating copy to clipboard operation
crocks copied to clipboard

Formal API for creating new ADTs

Open leeor opened this issue 6 years ago • 8 comments

First of all, impressive library! Really fun to work with.

I'd like to suggest making defineUnion part of the library's API. While there are other libraries that are specifically dedicated to creating new ADTs, the APIs you end up are quite different, which leads to inconsistencies in the code base. Some types are using one form of pattern matching, others use a different API.

What's missing (IMHO):

  • Exporting defineUnion functionality
  • Support for (de)serialising ADTs

I'm willing to provide a PR if the concept is deemed worthy.

leeor avatar Apr 25 '18 19:04 leeor

Thanks for your kind words. So I have put a lot of thought into this and TBH, this is more a collection of ADT implementations. But boy oh boy there have been many times I just wanted a quick UnionType or to define some Ring for a data type specific to my domain, nothing really that could be used in the wild.

So in order to make this just a collection of known APIs, I am going to create a separate crocks-daggy as daggy does custom ADTs (will also see how this going and make a more generic based on the others like folktale adt, uniontypes, etc) you just pass it your 🌽structor/TypeRep and it will add all the stuff needed to get it to work in the crocks ecosystem.

I think we could also support serialization/deserialization in another lib as opposed to baking it into the types themselves. In the past of have just created my own (de)serializers. But I am open to ideas.

What are your thoughts on separate packages?

evilsoft avatar Apr 25 '18 20:04 evilsoft

Separate packages make perfect sense. The approach will provide users with more freedom and keep each package leaner.

leeor avatar Apr 25 '18 20:04 leeor

I'd be happy to start the work on crocks-daggy if you know what you want it to look like (or willing to start the discussion). I would like to migrate to crocks and having the ability to create my own ADTs with the same API is a blocker for me.

Are you willing to entertain this suggestion?

leeor avatar May 14 '18 15:05 leeor

Sorry it took so long to get back. Oh yeah I am always up to entertain suggestions such as these.

So I was thinking, it would be some function that took a daggy definition and gave back a new definition with the following addtions:

  • the TypeRep has an @@implements function. This function is of the form () -> [ String ], and returns a list of the FL methods in non-prefix form, for example a Monoid Functor with Setoid would be: [ 'empty', 'equals', 'concat', 'map' ]. (all TypeRep level functions should be reported, like of, empty, zero, etc). It will build this list based on the methods/functions of the provided daggy definition.

  • a @@type String property needs to be present on both the TypeRep and the instance (prototype) and should include the daggy typename and be prefixed with crocks-daggy like so: crocks-daggy/[typename] (Sanctuary Style)

  • both the instance and TypeRef should have a type method that returns the String TypeName type :: () -> String

  • All TypeRef functions should also appear as methods on the instance (prototype) in addition to the TypeRef, empty, of, etc.

  • All fantasy-land defined methods should have the function available in prefixed and non-prefixed names. For instance, if the original definition defines map on the prototype, then fantasy-land/map will be added to the prototype. We will just do this blindly, it is up to the user to make sure they have the proper map defined. Another example: Given that empty was provided on the TypeRep, fantasy-land/empty will be added to the TypeRep, and empty and fantasy-land/empty will be added to the instance (prototype) as well. We only add these aliases if they do not exist (like a polyfill).

  • inspect and toString should be added/overriden and provide the format TypeName value, providing Function if a function is the underlying value. (may wanna bring in the inspect from crocks)

That should be enough to get started. One thing to note, it is very important that we do not change the original definition, so we may need to create a dependency on daggy and return a new definition (but this could lead to version 🌽flicts, so I am curious what you come up with).

Also I started a repo (unless you wanted to own one), I will throw in a build system and specs and CI and all the goodies soon. crocks-daggy

evilsoft avatar May 20 '18 04:05 evilsoft

Had a while to think about this further and put crocks into more use, and I've come to realise that I was a bit wrong in my initial description of the problem (mostly due to a misunderstanding on my own part).

The missing element is actually pattern-matching API for crocks' types. I can use .either with a Maybe, Result, etc., but I can't use a more verbose notation where I actually pattern match on the type (like union-type's case).

This is both a pro and a con:

  1. Pro: I can use whatever union type library I want, and there won't be any confusion about the pattern matching APIs with the crocks' types.
  2. Con: obviously I cannot pattern match on crocks' types. This is useful for onboarding, making the code more verbose and easier to read.

Bottom line, the current situation allows me to mix & match crocks with any union type library without worrying about confusion APIs.

For interoperability of custom union types and crocks it would be helpful to have documentation that details the methods a type would require to be able to work with the different functions provided in crocks. For example, having to implement an either method to be able to use the either pointfree, or an ap for others, etc.

leeor avatar May 24 '18 15:05 leeor

Just to chime in on this, the pattern matching @leeor describes in their last comment makes a lot of sense to me (I've gone to use this sort of thing quite a few times and had to find alternate ways of working).

I'd also second a crocks-daggy package where we can create union types that interop with crocks by default. I love daggy because you can easily create taggedSums or single instances (without ending up in Person.Person() land like union-type). However, I'd love to see the _ wildcard pattern from union-type in a daggy like package as that saves an awful lot of needless repetition!

So, I guess, +1 - I'd love to help out if anything gets going

anatomic avatar Jul 06 '18 07:07 anatomic

I just want to second this request, some sister library or extension to define sum types and support for (de)serialization would be great. Not 100% sure on the dependency on Daggy. Although Daggy is great and I use it in almost all my projects, I am more of a fun of shallow dependency tree when it come to a choice. Also I would like to help out if needed.

bnenu avatar Jul 11 '18 06:07 bnenu

I was thinking, if we want union types. @karthikiyengar just added a n-Tuple type for simple Products, how would you all feel about a Union type that will provide something along the lines of a tagged-sum in daggy. But with a more crocks-y feel and API.

evilsoft avatar Jul 11 '18 17:07 evilsoft