Collections: OCaml standard library vs. Belt vs. Immutable-re


#1

I would like to use efficiently implemented immutable collections like Map, Set, etc. to store my application / component state.

What are the recommendations/best practices here? OCaml standard library? Belt? Immutable-re? (Well, I guess the latter is still “early alpha”…)

What are the pros and cons of each and what will be the future directions? Thanks!


Advice on standard library to use
#2

Immutable-re is currently unmaintained. Belt is in semi-private beta right now, though stable. What are you targeting? JS or native? And do you use dead code elimination?


#3

I am targeting JS. My project is set up using create-react-app/reason-scripts which uses a webpack version/setup that supports tree shaking as far as I understand.


#4

If your project isn’t too “serious”, it’d be great to have some initial feedback on Belt beta, its API, tree-shaking, etc. But if you’re just getting started, I’d say get the stuff done in either default stdlib Set/Map or Belt Set/Map. The switch is easy once you understand how things work.


#5

Thanks! Here is some very quick first feedback:

  • I much prefer the Belt function names over the stdlib function names, most of all because they make clear which functions throw exceptions and which don’t.
  • I do not like that the argument order in the Belt functions prevents me from (easily) chaining calls with the |> operator.

#6

Did you see that we released the pipe sugar? foo |> map(_, f)


#7

Yes, thanks! However, after installing the latest bs-platform, I thought at first that the pipe sugar didn’t work, because merlin always showed me syntax errors in VS code.

But bsb -make-world does work. Restarting VS code does not help. Weird.


#8

Yeah, sorry about that… not sure why I forgot to mention it. The global refmt (for editor) + merlin toolchain is a few days behind. Once reason-cli is upgraded, this issue will be resolved.


#9

No problem! Thank you for the information and thanks a lot for your great work!


#10

Regarding the chaining: It is certainly nice to have the pipe sugar.

However, I still think the different argument order in Belt is very confusing and inconsistent. Not just inconsistent with the OCaml stdlib, but also with the Js.Array and Js.String functions (where the argument order was changed from the JS version of the functions in order to support piping…).


#11

We’ll release a post regarding this soon.


#12

I agree with the @cknittel’s statement. I don’t understand how an “standard” library on an FP language has that weird params order.


#13

The only explanation I can think of is that fast pipe is actually the recommended piping method in Reason.


#14

As far as I’m aware, the only official “explanation”, if you can call it that, of the weird parameter order is this.


#15

We’ll release a post regarding this soon.

“soon”… lol


#16

Well, in this comment Bob Zhang mentions type inference & code completion as primary reasons.

But, yeah, I find switching from the normal pipes somewhat painful. Maybe it’s worth it though.


#17

That is a benefit, but seems to matter little in practice, and as Jordan points out later there’s similar issues in the reverse. Even if it did matter, piling on hacks to fix problems in the short term usually comes back to bite you later. Meanwhile, the cognitive cost alone of having to juggle multiple subtly different forms of piping is huge.

It doesn’t seem to matter what us plebs think about this anyway though.


#18

I have too little xp with functional languages to judge the matter properly. Including Elixir, where AFAIK fast pipes are the norm. I guess I’m gonna have to try a bit of both.


#19

It seems like the ML veterans (OCaml, Elm, Haskell, F#, etc) strongly prefer t-last while we Elixir fans prefer t-first and I think it’s more idiomatic for JS devs also (in a object method sort of way). It’s hard to envision the practical benefits of currying if you are experienced in a language that doesn’t have it.

I’m just happy we have the ability to do x |> y(_, arg2) since for some reason I much prefer that to the x->y(arg2)


#20

I’ve been working with Elixir as my main language for a couple of years. I find the T-first piping pattern productive but also constraining. In Elixir, a language without idiomatic currying, T-first piping makes function composition practical. I do find that it often forces the hand into a something of a imperative functional style where you often get/transform data then pass it along, rather than build up a deeply composed function that is then evaluated with data closer to a boundary layer.

I’m just a tourist here for now, doing a little window shopping before going back to my Lodash/FP day job, but I get the sense that T-first would work well here.