How to return the index of a for loop in OCaml?

霸气de小男生 提交于 2019-12-23 08:38:39

问题


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

How can i return the index of a loop as an integer once the match has been found?


回答1:


If you want to stick to the imperative style, you can use an exception to exit the loop:


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

But generally, as ppl have already written, functional style is more preferred in 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

In this example, there is not much difference between the two versions, but use of exceptions for exiting loops/recursions must be used with caution; you can introduce control flow bugs pretty easily with them, and they are sometimes hard to debug.

BTW, you can use Array.unsafe_get heap i to speed up your array access since you can be sure that i is always in the valid range of the array the above examples. (Oh, we need start >= 0 check in addition, though.)




回答2:


Asumu Takikawa is right, the for loop in OCaml doesn't return a result. In idiomatic OCaml, you should use recursion instead. Ideally there would be a standard function like List.find that works for arrays. There is a function BatArray.findi in OCaml Batteries Included that does what you seem to want.




回答3:


Simpler, and more efficient (no allocation at all):

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)

Or, in imperative style:

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

(notice that raise exit does not allocate only because the exception if precomputed).




回答4:


Loops in Ocaml are supposed to be imperative, so it shouldn't return a result (aside from unit). So if you try to return a non-unit result, the compiler will give a warning.

The reason that Ocaml doesn't let you return a result from a loop is because this isn't a very functional idiom. If you use a recursive function instead of a loop, it's easy to exit early and return a result (by returning the result instead of recurring). If you want to write idiomatic Ocaml, you probably want to use recursion in this case.



来源:https://stackoverflow.com/questions/9458859/how-to-return-the-index-of-a-for-loop-in-ocaml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!