2012-02-27 14 views
8
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 

Jak mogę zwrócić indeks pętli jako liczbę całkowitą po znalezieniu dopasowania?Jak zwrócić indeks pętli for w OCaml?

Odpowiedz

8

Jeśli chcesz trzymać się imperatywem stylu, można użyć wyjątek, aby wyjść z pętli:


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 

ale generalnie, jak ppl już napisany, styl funkcjonalny jest bardziej korzystne SML:


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 

W tym przykładzie nie ma dużej różnicy między obiema wersjami, ale należy zachować ostrożność przy korzystaniu z wyjątków dla wychodzących pętli/rekurencji; można z nimi łatwo wprowadzać błędy sterowania, a czasem trudno je debugować.

BTW, możesz użyć sterty Array.unsafe_get i, aby przyspieszyć dostęp do tablicy, ponieważ możesz być pewien, że i jest zawsze w prawidłowym zakresie tablicy powyższych przykładów. (Oh, musimy zacząć> = 0 Sprawdź Ponadto, choć.)

4

Pętle w Ocaml mają być konieczne, więc nie powinny zwracać wyniku (poza jednostką). Więc jeśli spróbujesz zwrócić wynik nie jednostkowy, kompilator da ostrzeżenie.

Powodem, dla którego Ocaml nie pozwala na zwrócenie wyniku z pętli, jest to, że nie jest to bardzo funkcjonalny idiom. Jeśli używasz funkcji rekursywnej zamiast pętli, łatwo jest wyjść wcześniej i zwrócić wynik (zwracając wynik zamiast powtarzania). Jeśli chcesz napisać idiomatyczny Ocaml, prawdopodobnie będziesz chciał użyć rekursji w tym przypadku.

5

Asumu Takikawa ma rację, pętla for w OCaml nie zwraca wyniku. W idiomatycznym OCaml powinieneś używać rekurencji. Idealnie byłoby mieć standardową funkcję, taką jak List.find, która działa dla tablic. Istnieje funkcja BatArray.findi w OCaml Batteries Included, która robi to, czego oczekujesz.

5

prostsze i bardziej wydajne (brak podziału na wszystkie):

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) 

lub w bezwzględnej styl:

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 

(należy zauważyć, że raise exit nie przydziela tylko ze względu na wyjątek, jeśli jest wstępnie skompilowany).

+0

Przez "wyjątek jest wstępnie obliczony", masz na myśli to, że dodanie 'let exit = Exit' przed pętlą jest tym, co zapobiega tutaj niektórym nieefektywnościom? Czy nadal miałoby to miejsce w przypadku ostatniego kompilatora OCaml? – anol