Как в общем случае пройти по массиву в ReScript?
Допустим, я хочу перебрать массив способом, который не поддерживается
Js
/Belt
стандартные библиотечные функции. Например, возможно, мне нужно исследовать пары элементов за раз. Со списком это просто сделать в рекурсивном стиле:
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
Однако ReScript, кажется, мягко отговаривает списки в пользу массивов (см.: более неуклюжий синтаксис списков и отсутствие списковых эквивалентов некоторых стандартных библиотечных функций, таких как
Belt.Map.fromArray
), поэтому я не уверен, что преобразование массива в список только для использования этого стиля идиоматично, особенно если функция создает список, который затем должен превратиться обратно в массив.
Конечно, я могу использовать изменчивость для реализации функции традиционным императивным способом:
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
Но это уродливо и противоречит функциональным возможностям ReScript.
Каков простой идиоматический способ реализовать эту функцию?
1 ответ
Вы по-прежнему можете использовать рекурсию, просто увеличивая индекс вместо использования хвоста списка:
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)
}