Как в общем случае пройти по массиву в 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)
}
Другие вопросы по тегам