Skip to content

Commit 6e16d9a

Browse files
ryyppynkrkvwhitchapmanjihchiBartSchuurmans
authored andcommitted
Sync Belt / Js doc headers (rescript-lang#5361)
* Sync doc headers for belt.ml * Sync doc headers for belt_Array.mli * Update belt_Float.mli doc headers * Sync docs for belt_HashMap.mli * Sync docs for belt_HashMapInt.mli * Sync docs for belt_HashMapString.mli * Sync belt_HashSet.mli * Update belt_HashMapInt * Sync belt_HashSetString.mli * Sync docs for belt_Int.mli * Sync docs for belt_List.mli * Sync docs for belt_Option.mli * Adapt docs in belt_Option.mli for parts missing in rescript-lang.org MDX * Sync docs for belt_Result.mli * Sync docs for belt_Set.mli * Sync docs for belt_SetInt.mli * Sync docs for belt_SetString.mli * Sync docs for belt_SetDict.mli * Sync docs for belt_MutableSetInt.mli * Sync docs for belt_MutableSetString.mli * Sync all the docstring texts from sort-array.mdx * Remove duplication of type definitions * Sync all the docstring texts from sort-array-int.mdx * Sync docs for belt_Map.mli * Sync docs for belt_MapInt.mli * Sync docs for belt_MapString.mli * Sync docs for belt_MutableMap.mli * Sync docs for belt_MutableMapInt.mli * Sync docs for belt_MutableMapString.mli * Remove duplicate type signatures * Sync all the docstring texts from sort-array-string.mdx * Sync docs for belt_MutableSet.mli * Sync docs for belt_Range.mli * Sync docs for belt_MutableQueue.mli * Sync docs for belt_MutableStack.mli * Sync docs for Js.ml * Sync docs for js_array.ml * Sync docs for js_array2.ml * Sync docs for js_date.ml * Sync docs for js_dict.mli * Sync docs for js_exn.mli * Sync docs for js_float.ml * Sync docs for js_math.ml * Sync docs for js_option.ml * Sync docs of js_global.ml * Sync docs for js_int.ml * Sync docs for js_re.ml * Sync docs for js_json.mli * Sync docs for js_null.mli * Sync docs for js_null_undefined * Sync docs for js_obj.ml * Sync docs for js_promise.ml * Sync docs for js_string.ml * Fix misplaced doc in js_array2 * Sync docs for js_string2.ml * Update docs for js_types.mli * Sync docs for js_undefined.mli * Sync docs for js_vector.mli Co-authored-by: Patrick Ecker <ryyppy@users.noreply.github.com> Co-authored-by: Victor Nakoryakov <nail.xx@gmail.com> Co-authored-by: Whit Chapman <whit.chapman@gmail.com> Co-authored-by: jihchi <achi@987.tw> Co-authored-by: Bart Schuurmans <bart@minnozz.com>
1 parent d2ae554 commit 6e16d9a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+11396
-4143
lines changed

jscomp/others/belt.ml

+155-70
Original file line numberDiff line numberDiff line change
@@ -22,97 +22,183 @@
2222
* along with this program; if not, write to the Free Software
2323
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
2424

25-
(** A stdlib shipped with ReScript
25+
(** The ReScript standard library.
2626
27-
This stdlib is still in _beta_ but we encourage you to try it out and
28-
give us feedback.
27+
Belt is currently mostly covering collection types. It has no string or date functions yet, although Belt.String is in the works. In the meantime, use [Js.String](js/string) for string functions and [Js.Date](js/date) for date functions.
2928
30-
**Motivation**
29+
## Motivation
3130
32-
The motivation for creating such library is to provide ReScript users a
33-
better end-to-end user experience, since the original OCaml stdlib was not
34-
written with JS in mind. Below is a list of areas this lib aims to
35-
improve:
36-
1. Consistency in name convention: camlCase, and arguments order
37-
2. Exception thrown functions are all suffixed with _Exn_, e.g, _getExn_
38-
3. Better performance and smaller code size running on JS platform
31+
Belt provides:
3932
40-
**Name Convention**
33+
- The **highest quality** immutable data structures in JavaScript.
34+
- Safety by default: A Belt function will never throw exceptions, unless it is
35+
indicated explicitly in the function name (suffix "Exn").
36+
- Better performance and smaller code size running on the JS platform.
37+
- Ready for [Tree Shaking](https://webpack.js.org/guides/tree-shaking/).
4138
42-
For higher order functions, it will be suffixed **U** if it takes uncurried
43-
callback.
39+
## Usage
4440
45-
```
46-
val forEach : 'a t -> ('a -> unit) -> unit
47-
val forEachU : 'a t -> ('a -> unit [@bs]) -> unit
48-
```
41+
To use modules from Belt, either refer to them by their fully qualified name (`Belt.List`, `Belt.Array` etc.) or open the `Belt` module by putting
4942
50-
In general, uncurried version will be faster, but it may be less familiar to
51-
people who have a background in functional programming.
43+
```
44+
open Belt
45+
```
5246
53-
**A special encoding for collection safety**
47+
at the top of your source files. After opening Belt this way, `Array` will refer to `Belt.Array`, `List` will refer to `Belt.List` etc. in the subsequent code.
5448
55-
When we create a collection library for a custom data type we need a way to provide a comparator
56-
function. Take _Set_ for example, suppose its element type is a pair of ints,
57-
it needs a custom _compare_ function that takes two tuples and returns their order.
58-
The _Set_ could not just be typed as `Set.t (int * int)`, its customized _compare_ function
59-
needs to manifest itself in the signature, otherwise, if the user creates another
60-
customized _compare_ function, the two collection could mix which would result in runtime error.
49+
If you want to open Belt globally for all files in your project instead, you can put
6150
62-
The original OCaml stdlib solved the problem using _functor_ which creates a big
63-
closure at runtime and makes dead code elimination much harder.
64-
We use a phantom type to solve the problem:
51+
```json
52+
"bsc-flags": ["-open Belt"],
53+
```
6554
66-
```
67-
module Comparable1 = Belt.Id.MakeComparable(struct
68-
type t = int * int
69-
let cmp (a0, a1) (b0, b1) =
70-
match Pervasives.compare a0 b0 with
71-
| 0 -> Pervasives.compare a1 b1
72-
| c -> c
73-
end)
55+
into your `bsconfig.json`.
7456
75-
let mySet1 = Belt.Set.make ~id:(module Comparable1)
57+
**Note**: this is the **only** `open` we encourage.
7658
77-
module Comparable2 = Belt.Id.MakeComparable(struct
78-
type t = int * int
79-
let cmp (a0, a1) (b0, b1) =
80-
match Pervasives.compare a0 b0 with
81-
| 0 -> Pervasives.compare a1 b1
82-
| c -> c
83-
end)
59+
Example usage:
8460
85-
let mySet2 = Belt.Set.make ~id:(module Comparable2)
86-
```
61+
```
62+
let someNumbers = [1, 1, 4, 2, 3, 6, 3, 4, 2]
8763
88-
Here, the compiler would infer `mySet1` and `mySet2` having different type, so
89-
e.g. a `merge` operation that tries to merge these two sets will correctly fail.
64+
let greaterThan2UniqueAndSorted =
65+
someNumbers
66+
->Belt.Array.keep(x => x > 2)
67+
// convert to and from set to make values unique
68+
->Belt.Set.Int.fromArray
69+
->Belt.Set.Int.toArray // output is already sorted
9070
91-
```
92-
val mySet1 : ((int * int), Comparable1.identity) t
93-
val mySet2 : ((int * int), Comparable2.identity) t
94-
```
71+
Js.log2("result", greaterThan2UniqueAndSorted)
72+
```
9573
96-
`Comparable1.identity` and `Comparable2.identity` are not the same using our encoding scheme.
74+
## Curried vs. Uncurried Callbacks
9775
98-
**Collection Hierarchy**
76+
For functions taking a callback parameter, there are usually two versions
77+
available:
9978
100-
In general, we provide a generic collection module, but also create specialized
101-
modules for commonly used data type. Take _Belt.Set_ for example, we provide:
79+
- curried (no suffix)
80+
- uncurried (suffixed with `U`)
10281
103-
```
104-
Belt.Set
105-
Belt.Set.Int
106-
Belt.Set.String
107-
```
82+
E.g.:
10883
109-
The specialized modules _Belt.Set.Int_, _Belt.Set.String_ are in general more
110-
efficient.
84+
```
85+
let forEach: (t<'a>, 'a => unit) => unit
11186
112-
Currently, both _Belt_Set_ and _Belt.Set_ are accessible to users for some
113-
technical reasons,
114-
we **strongly recommend** users stick to qualified import, _Belt.Set_, we may hide
115-
the internal, _i.e_, _Belt_Set_ in the future
87+
let forEachU: (t<'a>, (. 'a) => unit) => unit
88+
```
89+
90+
The uncurried version will be faster in some cases, but for simplicity we recommend to stick with the curried version unless you need the extra performance.
91+
92+
The two versions can be invoked as follows:
93+
94+
```
95+
["a", "b", "c"]->Belt.Array.forEach(x => Js.log(x))
96+
97+
["a", "b", "c"]->Belt.Array.forEachU((. x) => Js.log(x))
98+
```
99+
100+
## Specialized Collections
101+
102+
For collections types like set or map, Belt provides both a generic module as well as specialized, more efficient implementations for string and int keys.
103+
104+
For example, Belt has the following set modules:
105+
106+
- [Belt.Set](belt/set)
107+
- [Belt.Set.Int](belt/set-int)
108+
- [Belt.Set.String](belt/set-string)
109+
110+
## Implementation Details
111+
112+
### Array access runtime safety
113+
114+
One common confusion comes from the way Belt handles array access. It differs from than the default standard library's.
115+
116+
```
117+
let letters = ["a", "b", "c"]
118+
let a = letters[0] // a == "a"
119+
let capitalA = Js.String.toUpperCase(a)
120+
let k = letters[10] // Raises an exception! The 10th index doesn't exist.
121+
```
122+
123+
Because Belt avoids exceptions and returns `options` instead, this code behaves differently:
124+
125+
```
126+
open Belt
127+
let letters = ["a", "b", "c"]
128+
let a = letters[0] // a == Some("a")
129+
let captialA = Js.String.toUpperCase(a) // Type error! This code will not compile.
130+
let k = letters[10] // k == None
131+
```
132+
133+
Although we've fixed the problem where `k` raises an exception, we now have a type error when trying to capitalize `a`. There are a few things going on here:
134+
135+
- Reason transforms array index access to the function `Array.get`. So `letters[0]` is the same as `Array.get(letters, 0)`.
136+
- The compiler uses whichever `Array` module is in scope. If you `open Belt`, then it uses `Belt.Array`.
137+
- `Belt.Array.get` returns values wrapped in options, so `letters[0] == Some("a")`.
138+
139+
Fortunately, this is easy to fix:
140+
141+
```res example
142+
open Belt
143+
let letters = ["a", "b", "c"]
144+
let a = letters[0]
145+
146+
// Use a switch statement:
147+
let capitalA =
148+
switch a {
149+
| Some(a) => Some(Js.String.toUpperCase(a))
150+
| None => None
151+
}
152+
153+
let k = letters[10] // k == None
154+
```
155+
156+
With that little bit of tweaking, our code now compiles successfully and is 100% free of runtime errors!
157+
158+
### A Special Encoding for Collection Safety
159+
160+
When we create a collection library for a custom data type we need a way to provide a comparator function. Take Set for example, suppose its element type is a pair of ints, it needs a custom compare function that takes two tuples and returns their order. The Set could not just be typed as Set.t (int \* int) , its customized compare function needs to manifest itself in the signature, otherwise, if the user creates another customized compare function, the two collection could mix which would result in runtime error.
161+
162+
We use a phantom type to solve the problem:
163+
164+
```
165+
module Comparable1 =
166+
Belt.Id.MakeComparable(
167+
{
168+
type t = (int, int)
169+
let cmp = ((a0, a1), (b0, b1)) =>
170+
switch Pervasives.compare(a0, b0) {
171+
| 0 => Pervasives.compare(a1, b1)
172+
| c => c
173+
}
174+
}
175+
)
176+
177+
let mySet1 = Belt.Set.make(~id=module(Comparable1))
178+
179+
module Comparable2 =
180+
Belt.Id.MakeComparable(
181+
{
182+
type t = (int, int)
183+
let cmp = ((a0, a1), (b0, b1)) =>
184+
switch Pervasives.compare(a0, b0) {
185+
| 0 => Pervasives.compare(a1, b1)
186+
| c => c
187+
}
188+
}
189+
)
190+
191+
let mySet2 = Belt.Set.make(~id=module(Comparable2))
192+
```
193+
194+
Here, the compiler would infer `mySet1` and `mySet2` having different type, so e.g. a `merge` operation that tries to merge these two sets will correctly fail.
195+
196+
```
197+
let mySet1: t<(int, int), Comparable1.identity>
198+
let mySet2: t<(int, int), Comparable2.identity>
199+
```
200+
201+
`Comparable1.identity` and `Comparable2.identity` are not the same using our encoding scheme.
116202
117203
*)
118204

@@ -256,7 +342,6 @@ module Result = Belt_Result
256342

257343
module Int = Belt_Int
258344

259-
260345
(** [`Belt.Float`]()
261346
262347
Utilities for Float.

0 commit comments

Comments
 (0)