Tablecloth & Standard merge, new API naming (Poll)


#1

Hey all,

In the process of merging Standard and Tablecloth we are trying to nail down what the new API will look like for the Option and Result modules.

We are struggling to decide on the name for this function in particular, named iter in the standard library and named forEach in Belt

let iter: (option('a), ~f:('a => unit)) => unit

So I thought in order to help us decide we would reach out to see what the community thought.

The main contenders:

  • iterate
  • forEach
  • run
  • execute
  • do_
  • tap
  • other (please comment)

0 voters


#2

As someone who only tried a few functional libraries (Jane Street Base, Belt, @most/core, and a bit of Elm) I find the frist two names the most clear for collections. Then again, forEach, IMHO, sounds a little silly for types that basically wrap a single value.

tap sounds familiar too, but I’m not even sure if its similarity with Fun.tap (which can be seen as the same tap, but for a naked value insdead of the values inside a collection) helps or confuses. Then again, with Option.tap or Result.tap it’s beginning to dawn on me, and maybe it’s even the best of all because it doesn’t imply iterating over multiple values.

But overall, I think maybe you have to look at it in a wider context, use the principle of least surprise and make things more consistent and easier to memorize? Do you want Set.iter, List.iter, Option.iter, but Fun.tap? Thats one boundary. Set.forEach, List.forEach, Option.tap and Fun.tap. Fine too, I guess, as long as it’s Result.tap (not forEach) as well, and Array.forEach (not tap). Going iter (or tap) all the way, including Fun.iter? Even better (arguably).

I think consistency beats familiarity even in the middle run (and Reason actualy shines in the long run, and will probably stay that way for quite a while, if not indefinitely). So don’t really care about forEach.


#3

Thanks, Arrays, Lists, Sets and Maps use forEach.


#4

I also settled on forEach for a library I’m developing.


#5

Using the same name for all types makes sense to me. When you know the operation you want to perform the name should be the same for any supported type.

forEach is what I’m used to from Scala.


#6

It’s also important for abstraction. If multiple modules have members with the same types, they can be abstracted over. E.g. if we have List, Array, Option, all with the same function let forEach: (t('a), ~f: 'a => unit) => unit, then we can create functions or functors which take those modules as an argument by just declaring the portion of the module they need:

module type Iterable = {
  type t('a);
  let forEach(t('a), ~f: 'a => unit) => unit;
};

Any module which has type t('a) and let forEach: ... is implicitly compatible with this module type, because of structural subtyping of modules.


#7

Thanks for doing this!


#8

I originally voted for tap because I think it’s semantically more exact for Option and Result compared to forEach but the ability to type the different modules with the same signature as @yawaramin mentioned it is so powerful that I think the same name should be favored, so forEach I guess.

Huge thanks for maintaining this, it’s extremely cool to see projects converging in the OCaml ecosystem, unfortunately unusual enough to be noticed and celebrated :slight_smile:


#9

I voted for forEach but I agree that consistency is way more important. So if it ends up being iter or something for consistency that’s cool by me


#10

@tsnobip While it’s nice to have module interface compatibility out of the box with forEach, it’s also quite easy to shim things like different naming conventions for standard functions. Just including the module implementation you want to use, and aliasing the incompatible function names should be enough. So I guess I’m not that concerned about it. So comprehensibility should probably come first & foremost.

That said, I think both tap and forEach are very intuitive as it is.


#11

I don’t know about that. I think standard libraries should work out of the box with as little ceremony as possible. True, for long-living project deficiencies (or lack) of standard libraries don’t matter so much, but why make bootstrapping harder for the whole community?

EDIT: spelling


#12

I’ve used .each for this concept for many years now, but .forEach is the standard most communities seem to have settled on. I think that’s fine.


#13

This is off-topic, and not at all trying to start an argument, but this desire for commonality and abstraction is precisely what things like Functor/Applicative/Monad are about. Cheng Lou keeps trying to steer every conversation away from things like monads, but what you are saying is important about commonality and abstraction is the same reason why Functor/etc. are useful and powerful. I don’t understand why it’s okay to promote abstractions like this example Iterable, but then we are directed to not talk about functors/applicatives/monads (not by you, but just in general). I think the FUD about monads and “FP ideas” is really hurting this community, and it stifling innovation, and the language is going to be left in the dust as a less-popular TypeScript. The reason I’m posting here is not at all to start an argument, but to encourage anyone who sees this message to just look at what a Functor is - it’s not much different than this Iterable. And then Applicative adds a layer on top of that, and in fact Monad is just another layer. Learning to use these things requires more work, but it’s worth it, so don’t buy into the fear of monads, and don’t give up if you’re trying to learn about them.


#14

Andy, while I may disagree on some specific implementation details, I think Relude is really cool. If you look around, you will find that I have (a) pushed for Reason to adopt OCaml’s let-operator syntax, (b) pushed for BuckleScript to do the same, and ( c ) pushed for the new syntax to at least support infix ops (since they are not planning to support let-ops).

I don’t know specifically about Cheng Lou but, I always caution newcomers to learn these things step by step. So first if we talk about something like module type Iterable and they see the value of modules conforming to that, then we can talk about Functor and so on. What I personally don’t want to do is dump a Haskell-like boat-load of category theory concepts on people learning the language. When they need it, they’ll know they need it and why. Reason is one of the most refactorable languages out there. If they need it, they will be able to use it.


#15

“… not planning to do let-ops” was that confirmed at one point? Last I heard it was just on hold for the moment… hmmm didn’t realise this PR was actually closed. https://github.com/BuckleScript/bucklescript/pull/4271


#16

See BuckleScript 8.1: new syntax option


#17

I think @whitehouse3001 is referring to this:

we’re not gonna become more like PureScript. To write PureScript, choose PureScript. And we’re not very interested in anything functors/applicative/monads beyond letting them exist. Infix can be discussed later. This is the last I’ll stay about this matter this week.

Specifically: “And we’re not very interested in anything functors/applicative/monads beyond letting them exist.”

re: https://discord.com/channels/235176658175262720/235176658175262720/728014718312251423

Abstraction is great, especially something as sound as FP. Thanks for teaching everyone so much of what you know @yawaramin!