Как вернуть индекс цикла for в OCaml? - PullRequest
8 голосов
/ 27 февраля 2012
let find_free_next heap start = 
  for i = start to ((Array.length heap)-1) do
     match heap.(i) with 
     Hdr (Free (h), g)  ->
        i
  done

Как я могу вернуть индекс цикла в виде целого числа, как только совпадение найдено?

Ответы [ 4 ]

8 голосов
/ 27 февраля 2012

Если вы хотите придерживаться императивного стиля, вы можете использовать исключение для выхода из цикла:


exception Found of int

let find_free_next heap start = 
  try
    for i = start to Array.length heap - 1 do
       match heap.(i) with 
       | Hdr (Free (h), g)  -> raise (Found i)
       | _ -> () (* If it is not what you are seeking *)
    done;
    raise Not_found   
  with
  | Found n -> n

Но, как правило, как уже писал ppl, функциональный стиль в OCaml более предпочтителен:


let find_free_next heap start =
  let len = Array.length heap in
  let rec find i =
    if i >= len then None
    else 
      match heap.(i) with
      | Hdr (Free h, g) -> Some i
      | _ -> find (i+1)
  in
  find start

В этом примере между этими двумя версиями нет большой разницы, но использование исключений для выхода из циклов / рекурсий следует использовать с осторожностью; с ними можно довольно легко вносить ошибки потока управления, а иногда их трудно отлаживать.

Кстати, вы можете использовать Array.unsafe_get heap i для ускорения доступа к вашему массиву, так как вы можете быть уверены, что i всегда находится в допустимом диапазоне массива в приведенных выше примерах. (О, нам нужно дополнительно проверить начало> = 0.)

5 голосов
/ 27 февраля 2012

Проще и эффективнее (без выделения):

let rec find_free_next heap start =
  if start = Array.length heap then raise Not_found;
  match heap.(i) with
  | Hdr (Free h, g) -> i
  | _ -> find_free_start heap (i+1)

Или, в императивном стиле:

let exit = Exit
let find_free_next heap start =
  let pos = ref (-1) in
  try
    for i = start to Array.length heap - 1 do
      match heap.(i) with
      | Hdr (Free h, g) -> pos := i; raise exit
      | _ -> ()
    done;
    raise Not_found
  with Exit -> !pos

(обратите внимание, что raise exit не выделяет только потому, что исключение, если предварительно вычислено).

5 голосов
/ 27 февраля 2012

Асуму Такикава прав, цикл for в OCaml не возвращает результат.В идиоматическом OCaml вы должны использовать рекурсию вместо этого.В идеале должна быть стандартная функция, такая как List.find, которая работает для массивов.Есть функция BatArray.findi в Аккумуляторы OCaml в комплекте , которые делают то, что вы хотите.

4 голосов
/ 27 февраля 2012

Циклы в Ocaml должны быть обязательными, поэтому они не должны возвращать результат (кроме единицы измерения).Поэтому, если вы попытаетесь вернуть результат, не относящийся к единице, компилятор выдаст предупреждение.

Причина, по которой Ocaml не позволяет вам вернуть результат из цикла, заключается в том, что это не очень функциональная идиома.,Если вы используете рекурсивную функцию вместо цикла, вы можете легко выйти раньше и вернуть результат (возвращая результат вместо повторения).Если вы хотите написать идиоматический Ocaml, вы, вероятно, захотите использовать рекурсию в этом случае.

...