I’m barely getting started. I was searching Belt for functions to transform between exceptions, result
, and option
. I continued searching and found Jane Street’s Base already had them. I especially love how it’s built up monadically with functors ensuring a consistent and broad shared API surface between “container types”. That was one of my big complaints with Elm’s standard library a couple years ago. It’s also built with ppx_let for async in the future. I assume Base was already considered. I just wondered historically why Belt doesn’t reuse it?
Why Belt vs Jane Street Base?
A few of Belt’s motivations are spelled out in the docs, but I think the one that most splits it from Base is:
- Better performance and smaller code size running on JS platform
which is not a main goal of Base, and which has systemic design implications. For example: the Belt authors specifically call out functor-based collections in the OCaml sodlib as making dead code elimination much harder.
Thanks @Riwsky that sounds like a plausible and reasonable context.
It’s a bummer 1) Base is much more comprehensive akin to Prelude. For instance I couldn’t find a corollary to either Option.try_next
or Result.try_with
in Belt. I find Container
functions like fold_until
generalizing List.every
and List.some
handy too. I suppose they aren’t onerous to write with vanilla pattern matches and/or recursion. I wonder is the API kept intentionally small? I assume the two libraries couldn’t interop over duplicated types like result
.
More vexing to me is 2) inconsistency between available functions. For instance Container
's iter
appears as List.forEach
yet neither in Option
nor Result
. What if there were Container
-like functors available or even confined to tests just to prove conformance of their monomorphic versions to some interface? Like don’t use them in real life unless you’re a library author checking you implemented a type the Reason way.
@texastoland I’ve raised the need for having some standardized interfaces in this PR: [Proposal] Belt Monads
Would be nice to see your concerns voiced there too perhaps we can come up with a pragmatic decision that provides correctness and consistency across the standard library, while remaining minimalistic and not forcing people to take a deep dive into Category Theory to work with it.
@Riwsky I mocked something up and don’t see any difference in JS between modules with/without functors. It’s not meant be to be a performant implementation nor a proposal for specific functions or operators (on the contrary I prefer Belt’s philosophy). Even if functors were bad unfancy signatures would still suffice to guarantee API consistency and availability across types.
@ostera I think it’s the right idea but:
- They aren’t built up hierarchically i.e.
Functor -> Applicative -> Monad
. - I don’t think operators would fly within the community at all.
- Prior art exists for implementation. What’s lacking is a core stakeholder to champion a common set of signatures for standard types (for libraries to implement too). The precise type classes are less important to me.
I guess the right way forward is a issue in BuckleScript?
Absolutely intentional. The aim was to not force people into understanding what constitutes a Monad from a categorical standpoint but rather to provide the least common denominator required for establishing well-behaved primitives in the library (Option, Result, Stream, Future, etc).
Also true! That’s why I included the more Java/Scala friendlier names such as flatMap
for >>=
and in the PR I propose orElse
for <|>
.
That’s what I’m trying to get started please voice the concerns on the PR. Perhaps that way we can gain momentum and define at the very least some interfaces we can all rely on.
@ostera would you be down for opening an issue and working back toward a PR? I view the steps as:
- Convince a maintainer that signatures of some form are necessary.
- Agree that any and all names are subject to change.
- Decide to what degree such signatures should reflect type classes.
- Decide whether to imitate an existing library.
- Decide what functions to include, functors or no, hierarchy or no. From my perspective the last is a given. It’s an implementation detail that gives you functions for free.
- PR/profit!
I have a draft of an RFC on interfaces that I’ll publish today I’ll get you a link as soon as it’s live.
@texastoland RFC 0001: Standard Library Interfaces — let’s get this discussion started! Feel free to submit a PR with changes, or even a second RFC that builds on top of it
@ostera just read it. Wow it was really superbly written. I understand your motivation for not breaking up the hierarchy. I say present that part as is for discussion. My inner Haskeller complains not all monoids are monads ect. but that’s too edge case to matter. Maybe Foldable
should include Traversable
? Anyway I think this is the perfect starting point. Thanks for making it!
What needs to happen to move forward? Excerpt from Real World OCaml:
One problem with
Fqueue
is that the interface is quite skeletal. There are lots of useful helper functions that one might want that aren’t there. TheList
module, by way of contrast, has functions likeList.iter
, which runs a function on each element; andList.for_all
, which returnstrue
if and only if the given predicate evaluates to true on every element of the list. Such helper functions come up for pretty much every container type, and implementing them over and over is a dull and repetitive affair.As it happens, many of these helper functions can be derived mechanically from the
fold
function we already implemented. Rather than write all of these helper functions by hand for every new container type, we can instead use a functor to add this functionality to any container that has afold
function.We’ll create a new module,
Foldable
, that automates the process of adding helper functions to afold
-supporting container. As you can see,Foldable
contains a module signatureS
which defines the signature that is required to support folding; and a functorExtend
that allows one to extend any module that matchesFoldable.S
:
Also relevant to a recent tweet about standardizing Promise function names.