Как в общем случае пройти по массиву в ReScript?

Допустим, я хочу выполнить итерацию по массиву способом, который плохо поддерживается _1 _ / _ 2_ функциями стандартной библиотеки. Например, возможно, мне нужно исследовать пары элементов за раз. Со списком это просто сделать в рекурсивном стиле:

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.

Какой простой идиоматический способ реализовать эту функцию?


person ezrast    schedule 10.09.2020    source источник


Ответы (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)
}
person glennsl    schedule 10.09.2020