如何在OCaml中返回for循环的索引?

时间:2012-02-27 01:00:47

标签: functional-programming ocaml

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 个答案:

答案 0 :(得分:8)

如果您想坚持命令式样式,可以使用异常退出循环:


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来加速你的数组访问,因为你可以确定我总是在上面例子的数组的有效范围内。 (哦,我们需要另外开始> = 0检查。)

答案 1 :(得分:5)

Asumu Takikawa是对的,OCaml中的for循环不会返回结果。在惯用的OCaml中,您应该使用递归。理想情况下,会有一个标准函数,如List.find,适用于数组。 BatArray.findi中有一个功能OCaml Batteries Included可以完成你想要的功能。

答案 2 :(得分:5)

更简单,更有效(根本没有分配):

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不会仅因为预先计算的例外而分配。

答案 3 :(得分:4)

Ocaml中的循环应该是必要的,所以它不应该返回结果(除了单位)。因此,如果您尝试返回非单位结果,编译器将发出警告。

Ocaml不允许您从循环返回结果的原因是因为这不是一个非常实用的习惯用法。如果使用递归函数而不是循环,则很容易提前退出并返回结果(通过返回结果而不是重复出现)。如果你想编写惯用的Ocaml,你可能想在这种情况下使用递归。