问题
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