Как мне в общем случае выполнить обход массива в ReScript?

#arrays #rescript

#массивы #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)) amp;amp; (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)
}