Let's say I want to iterate over an array in a way that isn't well-supported by the Js
/Belt
standard library functions. For example, perhaps I need to examine pairs of elements at a time. With a list, this is straightforward to do in a recursive style:
let rec findDouble = (list) => switch list {
| list{a, b, ..._} when a == b => a
| list{_, b, ...rest} => findDouble(list{b, ...rest})
| _ => 0
}
list{7, 9, 10, 10, 11, 13} |> findDouble |> Js.log // 10
However, ReScript seems to gently discourage lists in favor of arrays (see: the clumsier list syntax and the absence of list equivalents of certain standard library functions like Belt.Map.fromArray
), so I'm not sure if converting an array to a list just to use this style is idiomatic - especially if the function produces a list that must then turn back into an array.
Of course I can use mutability to implement the function in a traditional imperative way:
let findDouble = (arr) => {
let idx = ref(1)
let answer = ref(0)
while (idx.contents < Js.Array.length(arr)) && (answer.contents == 0) {
if arr[idx.contents] == arr[idx.contents - 1] {
answer := arr[idx.contents]
}
idx := idx.contents + 1
}
answer.contents
}
[7, 9, 10, 10, 11, 13] |> findDouble |> Js.log // 10
But this is ugly and runs counter to the functional bones of ReScript.
What is a clean, idiomatic way to implement this function?
You can still use recursion, just with incrementing an index instead of using the tail of the list:
let findDouble = arr => {
let rec loop = idx =>
if idx >= Array.length(arr) {
0
} else if arr[idx] == arr[idx - 1] {
arr[idx]
} else {
loop(idx + 1)
}
loop(1)
}