2012-02-27 10 views

Respuesta

8

Si usted quiere meter al estilo imperativo, puede utilizar una excepción para salir del bucle:


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 

Pero, en general, como PPL ya han escrito, estilo funcional es más preferido en 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 

En este ejemplo, no hay mucha diferencia entre las dos versiones, pero el uso de excepciones para salir de bucles/recursiones debe usarse con precaución; puede introducir errores de flujo de control con facilidad, y a veces es difícil depurarlos.

Por cierto, puede utilizar Array.unsafe_get heap i para acelerar su acceso a la matriz, ya que puede estar seguro de que siempre estoy en el rango válido de la matriz de los ejemplos anteriores. (Oh, necesitamos empezar> = 0 cheque, además, sin embargo.)

4

Se supone que los bucles en Ocaml son imperativos, por lo que no deberían arrojar un resultado (aparte de la unidad). Entonces, si intentas devolver un resultado que no sea unitario, el compilador dará una advertencia.

La razón por la que Ocaml no le permite devolver un resultado de un bucle es porque no es una expresión muy funcional. Si usa una función recursiva en lugar de un bucle, es fácil salir temprano y devolver un resultado (devolviendo el resultado en lugar de recurrir). Si quieres escribir Ocaml idiomático, probablemente quieras recurrir en este caso.

5

Asumu Takikawa tiene razón, el ciclo for en OCaml no devuelve ningún resultado. En OCaml idiomático, debería usar recursion en su lugar. Idealmente, habría una función estándar como List.find que funciona para matrices. Hay una función BatArray.findi en OCaml Batteries Included que hace lo que parece querer.

5

más simple y más eficiente (sin asignación en absoluto):

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) 

O, en el estilo imperativo:

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 

(tenga en cuenta que raise exit no se asigna solo porque la excepción es precalculada).

+0

Por "la excepción está precalculada", ¿quiere decir que agregar 'let exit = Exit' antes del bucle es lo que evita algunas ineficiencias aquí? ¿Sería este el caso con un compilador OCaml reciente? – anol

Cuestiones relacionadas