`Belt_List`

Utilities for List data type.

This module is compatible with original ocaml stdlib. In general, all functions comes with the original stdlib also applies to this collection, however, this module provides faster and stack safer utilities

`let length: t('a) => int;`

`length xs`

`let head: t('a) => option('a);`

`head xs`

returns `None`

if `xs`

is the empty list, otherwise it returns `Some value`

where `value`

is the first element in the list.

```
head [] = None ;;
head [1;2;3] = Some 1 ;;
```

`tail xs`

returns `None`

if `xs`

is empty; otherwise it returns `Some xs2`

where `xs2`

is everything except the first element of `xs`

;

```
tail [] = None;;
tail [1;2;3;4] = Some [2;3;4];;
```

`let get: t('a) => int => option('a);`

`get xs n`

return the nth element in `xs`

, or `None`

if `n`

is larger than the length

```
get [0;3;32] 2 = Some 32 ;;
get [0;3;32] 3 = None;;
```

`let make: int => 'a => t('a);`

`make n v`

- return a list of length
`n`

with each element filled with value`v`

- return the empty list if
`n`

is negative

`make 3 1 = [1;1;1]`

`let makeByU: int => Js.Fn.arity1((int => 'a)) => t('a);`

`let makeBy: int => (int => 'a) => t('a);`

`makeBy n f`

- return a list of length
`n`

with element`i`

initialized with`f i`

- return the empty list if
`n`

is negative

```
makeBy 5 (fun i -> i) = [0;1;2;3;4];;
makeBy 5 (fun i -> i * i) = [0;1;4;9;16];;
```

`drop xs n`

return the list obtained by dropping the first `n`

elements, or `None`

if `xs`

has fewer than `n`

elements

```
drop [1;2;3] 2 = Some [3];;
drop [1;2;3] 3 = Some [];;
drop [1;2;3] 4 = None;;
```

`take xs n`

return a list with the first `n`

elements from `xs`

, or `None`

if `xs`

has fewer than `n`

elements

```
take [1;2;3] 1 = Some [1];;
take [1;2;3] 2 = Some [1;2];;
take [1;2;3] 4 = None;;
```

`let splitAt: t('a) => int => option((list('a), list('a)));`

`splitAt xs n`

split the list `xs`

at position `n`

return None when the length of `xs`

is less than `n`

`splitAt [0;1;2;3;4] 2 = Some ([0;1], [2;3;4])`

`concatMany a`

return the list obtained by concatenating in order all the lists in array `a`

`concatMany [| [1;2;3] ; []; [3]; [4] |] = [1;2;3;3;4]`

`reverseConcat xs ys`

is equivalent to `concat (reverse xs) ys`

`reverseConcat [1;2] [3;4] = [2;1;3;4]`

`flatten ls`

return the list obtained by concatenating in order all the lists in list `ls`

`flatten [ [1;2;3] ; []; [3]; [4] ] = [1;2;3;3;4]`

`let mapU: t('a) => Js.Fn.arity1(('a => 'b)) => t('b);`

`map xs f`

return the list obtained by applying `f`

to each element of `xs`

`map [1;2] (fun x-> x + 1) = [3;4]`

`let zipByU: t('a) => t('b) => Js.Fn.arity2(('a => 'b => 'c)) => t('c);`

`zipBy xs ys f`

**See** `zip`

Equivalent to `zip xs ys |> List.map (fun (x,y) -> f x y)`

`zipBy [1;2;3] [4;5] (fun a b -> 2 * a + b) = [6;9];;`

`let mapWithIndexU: t('a) => Js.Fn.arity2((int => 'a => 'b)) => t('b);`

`mapWithIndex xs f`

applies `f`

to each element of `xs`

. Function `f`

takes two arguments: the index starting from 0 and the element from `xs`

.

```
mapWithIndex [1;2;3] (fun i x -> i + x) =
[0 + 1; 1 + 2; 2 + 3 ]
```

`let fromArray: array('a) => t('a);`

`fromArray arr`

converts the given array to a list

`fromArray [|1;2;3|] = [1;2;3]`

`let toArray: t('a) => array('a);`

`toArray xs`

converts the given list to an array

`toArray [1;2;3] = [|1;2;3|]`

`reverse xs`

returns a new list whose elements are those of `xs`

in reverse order.

`reverse [1;2;3] = [3;2;1]`

`let mapReverseU: t('a) => Js.Fn.arity1(('a => 'b)) => t('b);`

`mapReverse xs f`

Equivalent to `reverse (map xs f)`

`mapReverse [3;4;5] (fun x -> x * x) = [25;16;9];;`

`let forEachU: t('a) => Js.Fn.arity1(('a => 'b)) => unit;`

`let forEach: t('a) => ('a => 'b) => unit;`

`forEach xs f `

Call `f`

on each element of `xs`

from the beginning to end. `f`

returns `unit`

, so no new array is created. Use `foreach`

when you are primarily concerned with repetitively creating side effects.

```
forEach ["a";"b";"c"] (fun x -> Js.log("Item: " ^ x));;
(* prints:
Item: a
Item: b
Item: c
*)
let us = ref 0;;
forEach [1;2;3;4] (fun x -> us := !us + x);;
!us = 1 + 2 + 3 + 4;;
```

`let forEachWithIndexU: t('a) => Js.Fn.arity2((int => 'a => 'b)) => unit;`

`let forEachWithIndex: t('a) => (int => 'a => 'b) => unit;`

`forEachWithIndex xs f`

```
forEach ["a";"b";"c"] (fun i x -> Js.log("Item " ^ (string_of_int i) ^ " is " ^ x));;
(* prints:
Item 0 is a
Item 1 is b
Item 2 is cc
*)
let total = ref 0 ;;
forEachWithIndex [10;11;12;13] (fun i x -> total := !total + x + i);;
!total = 0 + 10 + 1 + 11 + 2 + 12 + 3 + 13;;
```

`let reduceU: t('a) => 'b => Js.Fn.arity2(('b => 'a => 'b)) => 'b;`

`let reduce: t('a) => 'b => ('b => 'a => 'b) => 'b;`

`reduce xs f`

Applies `f`

to each element of `xs`

from beginning to end. Function `f`

has two parameters: the item from the list and an “accumulator”, which starts with a value of `init`

. `reduce`

returns the final value of the accumulator.

```
reduce [1;2;3;4] 0 (+) = 10;;
reduce [1;2;3;4] 10 (-) = 0;;
reduce [1;2;3;4] [] add = [4;3;2;1];
```

```
let reduceWithIndexU:
t('a) =>
'b =>
Js.Fn.arity3(('b => 'a => int => 'b)) =>
'b;
```

`let reduceWithIndex: t('a) => 'b => ('b => 'a => int => 'b) => 'b;`

`reduceWithIndex xs f`

Applies `f`

to each element of `xs`

from beginning to end. Function `f`

has three parameters: the item from the list and an “accumulator”, which starts with a value of `init`

and the index of each element. `reduceWithIndex`

returns the final value of the accumulator.

`reduceWithIndex [1;2;3;4] 0 (fun acc x i -> acc + x + i) = 16;;`

`let reduceReverseU: t('a) => 'b => Js.Fn.arity2(('b => 'a => 'b)) => 'b;`

`let reduceReverse: t('a) => 'b => ('b => 'a => 'b) => 'b;`

`reduceReverse xs f`

Works like `reduce`

, except that function `f`

is applied to each item of `xs`

from the last back to the first.

```
reduceReverse [1;2;3;4] 0 (+) = 10;;
reduceReverse [1;2;3;4] 10 (-) = 0;;
reduceReverse [1;2;3;4] [] add = [1;2;3;4];;
```

`let mapReverse2U: t('a) => t('b) => Js.Fn.arity2(('a => 'b => 'c)) => t('c);`

`mapReverse2 xs ys f`

equivalent to `reverse (zipBy xs ys f)`

`mapReverse2 [1;2;3] [1;2] (+) = [4;2]`

`let forEach2U: t('a) => t('b) => Js.Fn.arity2(('a => 'b => 'c)) => unit;`

`forEach2 xs ys f`

stop with the shorter list

```
let reduce2U:
t('b) =>
t('c) =>
'a =>
Js.Fn.arity3(('a => 'b => 'c => 'a)) =>
'a;
```

`reduce2 xs ys init f `

Applies `f`

to each element of `xs`

and `ys`

from beginning to end. Stops with the shorter list. Function `f`

has three parameters: an “accumulator” which starts with a value of `init`

, an item from `xs`

, and an item from `ys`

. `reduce2`

returns the final value of the accumulator.

```
reduce2 [1;2;3] [4;5] 0 (fun acc x y -> acc + x * x + y) = 0 + (1 * 1 + 4) + (2 * 2 + 5);;
reduce2 [1;2;3] [4;5] [] (fun acc x y -> add acc (x + y) = [2 +5;1 + 4 ];; (*add appends at end *)
```

```
let reduceReverse2U:
t('a) =>
t('b) =>
'c =>
Js.Fn.arity3(('c => 'a => 'b => 'c)) =>
'c;
```

`reduceReverse2 xs ys init f `

Applies `f`

to each element of `xs`

and `ys`

from end to beginning. Stops with the shorter list. Function `f`

has three parameters: an “accumulator” which starts with a value of `init`

, an item from `xs`

, and an item from `ys`

. `reduce2`

returns the final value of the accumulator.

```
reduceReverse2 [1;2;3] [4;5] 0 (fun acc x y -> acc + x * x + y) = 0 + (1 * 1 + 4) + (2 * 2 + 5);;
reduceReverse2 [1;2;3] [4;5] [] (fun acc x y -> add acc (x + y) = [1 + 4;2 + 5];; (*add appends at end *)
```

`let everyU: t('a) => Js.Fn.arity1(('a => bool)) => bool;`

`let every: t('a) => ('a => bool) => bool;`

`every xs p`

`let someU: t('a) => Js.Fn.arity1(('a => bool)) => bool;`

`let some: t('a) => ('a => bool) => bool;`

`some xs p`

`let every2U: t('a) => t('b) => Js.Fn.arity2(('a => 'b => bool)) => bool;`

`every2 xs ys p`

returns true if predicate `p xi yi`

is true for all pairs of elements up to the shorter length (i.e. `min (length xs) (length ys)`

)

```
every2 [1;2;3] [0;1] (>) = true;;
every2 [] [1] (fun x y -> x > y) = true;;
every2 [2;3] [1] (fun x y -> x > y) = true;;
every2 [0;1] [5;0] (fun x y -> x > y) = false;
```

`let some2U: t('a) => t('b) => Js.Fn.arity2(('a => 'b => bool)) => bool;`

`some2 xs ys p`

returns true if `p xi yi`

is true for any pair of elements up to the shorter length (i.e. `min (length xs) (length ys)`

)

```
some2 [0;2] [1;0;3] (>) = true ;;
some2 [] [1] (fun x y -> x > y) = false;;
some2 [2;3] [1;4] (fun x y -> x > y) = true;;
```

`cmpByLength l1 l2`

Compare two lists solely by length. Returns -1 if `length l1`

is less than `length l2`

, 0 if `length l1`

equals `length l2`

, and 1 if `length l1`

is greater than `length l2`

.

```
cmpByLength [1;2] [3;4;5;6] = -1;;
cmpByLength [1;2;3] [4;5;6] = 0;;
cmpByLength [1;2;3;4] [5;6] = 1;;
```

`let cmpU: t('a) => t('a) => Js.Fn.arity2(('a => 'a => int)) => int;`

Compare elements one by one `f x y`

. `f`

returns

- a negative number if
`x`

is “less than”`y`

- zero if
`x`

is “equal to”`y`

- a positive number if
`x`

is “greater than”`y`

The comparison returns the first non-zero result of`f`

, or zero if`f`

returns zero for all`x`

and`y`

. If all items have compared equal, but`xs`

is exhausted first, return -1. (`xs`

is shorter) If all items have compared equal, but`ys`

is exhausted first, return 1 (`xs`

is longer)

```
cmp [3] [3;7] (fun a b -> compare a b) = -1
cmp [5;3] [5] (fun a b -> compare a b) = 1
cmp [|1; 3; 5|] [|1; 4; 2|] (fun a b -> compare a b) = -1;;
cmp [|1; 3; 5|] [|1; 2; 3|] (fun a b -> compare a b) = 1;;
cmp [|1; 3; 5|] [|1; 3; 5|] (fun a b -> compare a b) = 0;;
```

**Attention**: The total ordering of List is different from Array, for Array, we compare the length first and, only if the lengths are equal, elements one by one. For lists, we just compare elements one by one

`let eqU: t('a) => t('a) => Js.Fn.arity2(('a => 'a => bool)) => bool;`

`eq xs ys eqElem`

check equality of `xs`

and `ys`

using `eqElem`

for equality on elements, where `eqElem`

is a function that returns true if items `x`

and `y`

meet some criterion for equality, false otherwise. `eq`

false if length of `xs`

and `ys`

are not the same.

```
eq [1;2;3] [1;2] (=) = false ;;
eq [1;2] [1;2] (=) = true;;
eq [1; 2; 3] [-1; -2; -3] (fun a b -> abs a = abs b) = true;;
```

`let hasU: t('a) => 'b => Js.Fn.arity2(('a => 'b => bool)) => bool;`

`let has: t('a) => 'b => ('a => 'b => bool) => bool;`

`has xs eqFcn`

returns true if the list contains at least one element for which `eqFcn x`

returns true

```
has [1;2;3] 2 (=) = true;;
has [1;2;3] 4 (=) = false;;
has [-1;-2;-3] 2 (fun a b -> abs a = abs b) = true;;
```

`let getByU: t('a) => Js.Fn.arity1(('a => bool)) => option('a);`

`let getBy: t('a) => ('a => bool) => option('a);`

`getBy xs p`

returns `Some value`

for the first value in `xs`

that satisifies the predicate function `p`

; returns `None`

if no element satisifies the function.

```
getBy [1;4;3;2] (fun x -> x mod 2 = 0) = Some 4
getBy [15;13;11] (fun x -> x mod 2 = 0) = None
```

`let keepU: t('a) => Js.Fn.arity1(('a => bool)) => t('a);`

`keep xs p`

returns a list of all elements in `xs`

which satisfy the predicate function `p`

```
keep [1;2;3;4] (fun x -> x mod 2 = 0) =
[2;4]
```

`filter xs p`

returns a list of all elements in `xs`

which satisfy the predicate function `p`

```
filter [1;2;3;4] (fun x -> x mod 2 = 0) =
[2;4]
```

`let keepWithIndexU: t('a) => Js.Fn.arity2(('a => int => bool)) => t('a);`

`keepWithIndex xs p`

returns a list of all elements in `xs`

which satisfy the predicate function `p`

```
keepWithIndex [1;2;3;4] (fun _x i -> i mod 2 = 0)
=
[1;3]
```

`filterWithIndex xs p`

returns a list of all elements in `xs`

which satisfy the predicate function `p`

```
filterWithIndex [1;2;3;4] (fun _x i -> i mod 2 = 0)
=
[1;3]
```

`let keepMapU: t('a) => Js.Fn.arity1(('a => option('b))) => t('b);`

`keepMap xs f`

applies `f`

to each element of `xs`

. If `f xi`

returns `Some value`

, then `value`

is kept in the resulting list; if `f xi`

returns `None`

, the element is not retained in the result.

```
keepMap [1;2;3;4] (fun x -> if x mod 2 = 0 then Some (-x ) else None)
=
[-2;-4]
```

`let partitionU: t('a) => Js.Fn.arity1(('a => bool)) => (t('a), t('a));`

`partition xs p`

creates a pair of lists; the first list consists of all elements of `xs`

that satisfy the predicate function `p`

; the second list consists of all elements of `xs`

that do not satisfy `p`

```
partition [1;2;3;4] (fun x -> x mod 2 = 0) =
([2;4], [1;3])
```

`unzip xs`

takes a list of pairs and creates a pair of lists. The first list contains all the first items of the pairs; the second list contains all the second items.

```
unzip [(1,2) ; (3,4)] = ([1;3], [2;4]);;
unzip [(1,2) ; (3,4) ; (5,6) ; (7,8)] = ([1;3;5;7], [2;4;6;8]);;
```

```
let getAssocU:
t(('a, 'c)) =>
'b =>
Js.Fn.arity2(('a => 'b => bool)) =>
option('c);
```

`let getAssoc: t(('a, 'c)) => 'b => ('a => 'b => bool) => option('c);`

`getAssoc xs k eq`

return the second element of a pair in `xs`

where the first element equals `x`

as per the predicate function `eq`

, or `None`

if not found

```
getAssoc [ 1, "a"; 2, "b"; 3, "c"] 2 (=) = Some "b"
getAssoc [9, "morning"; 15, "afternoon"; 22, "night"] 3 (fun a b -> a mod 12 = b mod 12) = Some "afternoon"
```

`let hasAssocU: t(('a, 'c)) => 'b => Js.Fn.arity2(('a => 'b => bool)) => bool;`

`let hasAssoc: t(('a, 'c)) => 'b => ('a => 'b => bool) => bool;`

`hasAssoc xs k eq`

return true if there is a pair in `xs`

where the first element equals `k`

as per the predicate funtion `eq`

```
hasAssoc [1, "a"; 2, "b"; 3,"c"] 1 (=) = true;;
hasAssoc [9, "morning"; 15, "afternoon"; 22, "night"] 3 (fun a b -> a mod 12 = b mod 12) = true;;
```

```
let removeAssocU:
t(('a, 'c)) =>
'b =>
Js.Fn.arity2(('a => 'b => bool)) =>
t(('a, 'c));
```

`removeAssoc xs k eq`

Return a list after removing the first pair whose first value is `k`

per the equality predicate `eq`

; if not found, return a new list identical to `xs`

.

```
removeAssoc [1,"a"; 2, "b"; 3, "c" ] 1 (=) =
[2, "b"; 3, "c"]
removeAssoc [1,"a"; 2, "b"; 3, "c" ] 99 (=) =
[1, "a"; 2, "b"; 3, "c"]
```

```
let setAssocU:
t(('a, 'c)) =>
'a =>
'c =>
Js.Fn.arity2(('a => 'a => bool)) =>
t(('a, 'c));
```

`setAssoc xs k v eq`

if `k`

exists in `xs`

by satisfying the `eq`

predicate, return a new list with the key and value replaced by the new `k`

and `v`

; otherwise, return a new list with the pair `k, v`

added to the head of `xs`

.

```
setAssoc [1,"a"; 2, "b"; 3, "c"] 2 "x" (=) =
[1,"a"; 2, "x"; 3,"c"] ;;
setAssoc [1,"a"; 3, "c"] 2 "b" (=) =
[2,"b"; 1,"a"; 3, "c"]
setAssoc [9, "morning"; 3, "morning?!"; 22, "night"] 15 "afternoon"
(fun a b -> a mod 12 = b mod 12) = [9, "morning"; 15, "afternoon"; 22, "night"]
```

Note carefully the last example! Since `15 mod 12`

equals `3 mod 12`

, *both* the key and value are replaced in the list.

`let sortU: t('a) => Js.Fn.arity2(('a => 'a => int)) => t('a);`