Risto-Stevcev/bastet

Array.alt concats in reverse order

mlms13 opened this issue · 7 comments

Array.Alt.alt([|0, 1|], [|2, 3|]) == [|2, 3, 0, 1|];

This is because the definition is equal to Js.Array.concat which combines arrays in this order:

https://github.com/Risto-Stevcev/bs-abstract/blob/master/src/implementations/Array.re#L58

This seems unexpected to me, but I don't think it actually breaks any laws (it's still associative and distributive). If the current behavior isn't intended, I'm happy to submit a pull request.

It looks like it was written that way so that you can do something like this:

let _ = 
  [|2;3;4|]
  |> Js.Array.concat [|5;6;7|]
  |> Js.log

But it's different from the way it's implemented in javascript and purescript. Yeah I think you're right, we should probably change the current behavior so it's more intuitive and people can still use |. for that. I'll accept a PR 🙂

Just a note:

List.Alt.alt([0, 1], [2, 3]) == [0, 1, 2, 3]

I think Array should work the same as List.

I was thinking about this some more, and I'm thinking maybe it's not a bad idea to create some Belt interfaces of all of these things for "target first" (Belt.Monoid, Belt.Functor, etc). That way we'll have abstractions that cover the Belt API and we can then use the Belt version for this instead of introducing a breaking change.
What do you guys think?

I hadn't thought about the fact that usually the "significant" argument comes last, and in the case of alt, you could definitely argue that most significant array is the one being concat'd onto.

This initially came up because it feels especially wrong with the <|> infix:

let (<|>) = BsAbstract.Array.Infix.(<|>);
let combined = [| 0, 1, 2 |] <|> [| 3, 4, 5 |]; // [| 3, 4, 5, 0, 1, 2 |]

If you want to make significant-data-first modules for better compatibility with Belt, I won't try to stop you, but I also doubt I'd use them. 🙂 I generally prefer significant-data-last, but mostly I want typeclass-inspired functions that work like the PureScript equivalents, and alt is the one outlier (that I've seen so far).

It looks like implementations/Array.re uses a mix of functions from ArrayLabels and BuckleScript's Js.Array, and in this case, ArrayLabels.append would concat the arrays in the expected order, even though ArrayLabels is usually significant-data-last.

Yeah that's true, the operators really should be intuitive and compatible with purescript/haskell semantics. I don't really use Belt much either, but I'll still probably add some Belt interfaces eventually since it's used by Relude and some people like it.

With #11 merged, I'm happy to call this good. I'd be interested in talking more about Belt implementations modules and implementations that work better on native, which came up in that PR.