Belt
A stdlib shipped with Melange
This stdlib is still in beta but we encourage you to try it out and give us feedback.
Motivation
The motivation for creating such library is to provide Melange users a better end-to-end user experience, since the original OCaml stdlib was not written with JS in mind. Below is a list of areas this lib aims to improve:
Name Convention
For higher order functions, it will be suffixed U if it takes uncurried callback.
val forEach : 'a t -> ('a -> unit) -> unit
val forEachU : 'a t -> ('a -> unit [\@bs]) -> unit
In general, uncurried version will be faster, but it may be less familiar to people who have a background in functional programming.
A special encoding for collection safety
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.
The original OCaml stdlib solved the problem using functor which creates a big closure at runtime and makes dead code elimination much harder. We use a phantom type to solve the problem:
module Comparable1 = Belt.Id.MakeComparable(struct
type t = int * int
let cmp (a0, a1) (b0, b1) =
match Pervasives.compare a0 b0 with
| 0 -> Pervasives.compare a1 b1
| c -> c
end)
let mySet1 = Belt.Set.make ~id:(module Comparable1)
module Comparable2 = Belt.Id.MakeComparable(struct
type t = int * int
let cmp (a0, a1) (b0, b1) =
match Pervasives.compare a0 b0 with
| 0 -> Pervasives.compare a1 b1
| c -> c
end)
let mySet2 = Belt.Set.make ~id:(module Comparable2)
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.
val mySet1 : ((int * int), Comparable1.identity) t
val mySet2 : ((int * int), Comparable2.identity) t
Comparable1.identity
and Comparable2.identity
are not the same using our encoding scheme.
Collection Hierarchy
In general, we provide a generic collection module, but also create specialized modules for commonly used data type. Take Belt.Set for example, we provide:
Belt.Set
Belt.Set.Int
Belt.Set.String
The specialized modules Belt.Set.Int, Belt.Set.String are in general more efficient.
Currently, both Belt_Set and Belt.Set are accessible to users for some technical reasons, we strongly recommend users stick to qualified import, Belt.Set, we may hide the internal, i.e, Belt_Set in the future
module Array = Belt_Array;
module SortArray = Belt_SortArray;
module MutableQueue = Belt_MutableQueue;
module MutableStack = Belt_MutableStack;
module Range = Belt_Range;
module MutableSet = Belt_MutableSet;
module MutableMap = Belt_MutableMap;
module HashSet = Belt_HashSet;
module HashMap = Belt_HashMap;
module Option = Belt_Option;
Utilities for result data type.
module Result = Belt_Result;
Utilities for Int.
module Int = Belt_Int;
Utilities for Float.
module Float = Belt_Float;