Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Standard Library Interfaces #2843

Closed
wants to merge 2 commits into from

Conversation

leostera
Copy link
Collaborator

@leostera leostera commented May 26, 2018

Hello!

Note: this PR evolved into an RFC for standard library interfaces.

I'm opening this PR both as a question and sketched out proposal, since I see that there are some libraries starting to sprout that implement and reimplement map, flatMap, value/of/return for different datatypes:

  • Belt.Option
  • Belt.Result
  • Future from reason-future
  • Effect and Affect from bs-effects
  • Stream from bs-highland

And other libraries that would provide very interesting, fertile ground, such as Streams, monadic state handling, etc, would have to do the same thing over and over again.

Perhaps it's time Belt offers these functors and module signatures to unite how we will deal with these well-known, sound abstraction without having everyone rewrite or rename them 😄

Additionally, because Belt would own these signatures and the main functors, any optimizations could be done en-masse to all the libraries implementing them. Would be pretty sweet to optimize the default implementation of flatMap and get a boost across the whole ecosystem 🎉

I included also two instances for Result and Option, but I'm having some trouble setting up and testing this locally.

Help would be much appreciated 🙏

Note: the signature/functors heavily borrows from JaneStreet's Core lib, which halfway implementing my own I realized made sense to mostly use as a reference since theirs has been under heavy usage for quite some time.

PS: ReasonML port here (https://github.com/ostera/tldr.jsx/tree/reasonable-tldr/src/Control) 💃

@gilbert
Copy link

gilbert commented May 27, 2018

Hi @Ostera, can you give an example of how this is used? I'm curious to see what it looks like in code.

@leostera
Copy link
Collaborator Author

@gilbert if you look into the second commit you'll see how we can define instances for Option and Result.

If we were to use some of the operations from these instances, we could write:

open Belt;

let a = Some(1);
let f = x => Some(x+1);
let g = x => x+1;

let b: option(int) = Option.( a >>= f >>| g );

Which makes declaring how to compute with values of an Option much more succinct — same goes for any other monad that gets instantiated with these functor.

If we were to define a monad instance for reason-future we would do something like:

include (
  Monad.Make(
    {
      type t('a) = Future.t('a);
      let return = Future.value;
      let bind = Future.flatMap;
    },
  ):
    Monad.S with type t('a) := Future.t('a)
);

And automatically we get properly typed, working operators and functions (such as join, ignore, map, >>=, etc).

Naturally we can provide both >>= and flatMap, and >>| and map since they are simply aliases for each other 😃— the point is not to impose some operator-heavy notation, but merely to not have to redefine all of these common functions over and over and instead share how we declare and define them.

Hope this helps!

@gilbert
Copy link

gilbert commented May 29, 2018

Ahh ok, I missed the part where each datatype includes the Monad.Make in their own respective module definitions. Now everything makes sense, thank you!

@scull7
Copy link

scull7 commented Jun 18, 2018

Perhaps this may help identify some of the possible interface functions: https://github.com/scull7/bs-result

@leostera
Copy link
Collaborator Author

leostera commented Jun 18, 2018

@scull7 Absolutely! I see a few there: Applicative, Functor, Monad, BiFunctor, Foldable.

It’d be nice to make the “correct” choice but let’s try to be pragmatic. We shouldn’t need to be versed in Category Theory to implement standardized interfaces.

I’d propose we at least implement Monad (which includes Functor and Applicative) and consider throwing in:

  • Foldable — to collapse so many switches around Result/Optional, and make sure Streams and Futures always resolve to a value
  • and Alternative — to provide the common orElse / <|>.

@scull7
Copy link

scull7 commented Jun 20, 2018

Some more prior art: https://github.com/jonlaing/rationale

@leostera
Copy link
Collaborator Author

leostera commented Jun 26, 2018

For cross-reference, I've written an RFC to explain the issue and the proposal in more detail here: https://reasonsthlm.github.io/community-rfcs/text/0001-standard-library-interfaces.html

@leostera leostera changed the title [Proposal] Belt Monads [RFC] Standard Library Interfaces Jul 5, 2018
@bobzhang bobzhang closed this Mar 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants