2012-02-27 38 views

回答

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 

但是總體來說,如脂肪酶已經寫好,功能性風格更優選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堆來加速你的數組訪問,因爲你可以確定我總是在上述例子的數組的有效範圍內。 (哦,我們需要開始除> = 0檢查,雖然)。

4

Ocaml循環應該是必要的,所以它不應該返回結果(除了單位)。所以如果你試圖返回一個非單位結果,編譯器會給出警告。

Ocaml不讓你從循環中返回結果的原因是因爲這不是一個非常實用的習慣用法。如果使用遞歸函數而不是循環,則很容易退出並返回結果(通過返回結果而不是循環)。如果你想編寫慣用的Ocaml,你可能想在這種情況下使用遞歸。

5

Asumu Takikawa是對的,OCaml中的for循環沒有返回結果。在慣用的OCaml中,你應該使用遞歸來代替。理想情況下,會有一個標準功能,如List.find,適用於陣列。在OCaml Batteries Included中有一個功能BatArray.findi,它可以完成你想要的功能。

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不會因爲預先計算的異常而分配)。

+0

「異常是預先計算的」,是否意味着在循環之前添加'let exit = Exit'可以防止一些低效率?最近OCaml編譯器的情況會如此嗎? – anol 2015-06-19 08:39:19