2010-09-12 7 views
6

Al llegar a OCaml desde Lisp, me encuentro muy confundido acerca de cuándo las funciones vuelven y cuándo no. ¡Extraño mi cita mágica! Afortunadamente, la mayoría de las veces, OCaml parece saber automágicamente cuándo quiero que se evalúe una función y cuándo no. Sin embargo, frecuentemente intento asignar el valor de retorno de una función en una expresión let, como la siguiente.Asignación de garantía para el valor de retorno de una función en OCaml

let start = Sys.time in 
(* 
* do something here 
*) 
; 
let ending = Sys.time in 
Printf.printf "did something in %f seconds\n" (ending -. start) 

pero luego se queja ocamlc

Error: This Expression has type unit -> float 
     but an expression was expected of type float 

Me dice que inicio y final están obligados a Sys.time, no el valor de retorno de Sys.time.

¿Este comportamiento que estoy tratando de obtener no es OCamly? ¿Quiero hacer las cosas de otra manera? ¿Me estoy perdiendo algo completamente obvio?

Respuesta

10

Una función se evalúa cuando la aplica a un argumento. Es decir. cuando lo haga f, f nunca se evalúa. Cuando lo haga f x, f siempre se evalúa. No hay nada mágico al respecto.

Como ha señalado usted correctamente, Sys.time es una función (de tipo unit -> float) y let start = Sys.time simplemente asigna esa función a start.

Para obtener el comportamiento que desea simplemente hacer let start = Sys.time(), que se aplica la función Sys.time al argumento () (que es el único valor de tipo unit).

3

No puede llamar a una función simplemente escribiendo su nombre. Si solo escribe el nombre de una función, está devolviendo la función en sí, no su valor de retorno. Ese error indica que la función toma un argumento unit - es decir, debe escribir Sys.time() para aplicar realmente la función y obtener el valor resultante float.

0

Para ayudar a las personas que se utilizan para Lisp, yo diría que sólo hay dos reglas de evaluación en ocaml:

  • Retraso regla de cálculo de: Un valor de la función, como fun x -> body, al no aplicarse a cualquier argumento , no será evaluado más. (La evaluación de un cuerpo de función está "retrasada"). En cambio, la expresión "cuerpo" se compila en código de computadora. Ese código de computadora es el "valor" real de la expresión de la función, y el código se ejecutará siempre que la función se aplique a un argumento.
  • Regla de evaluación ansiosa: Al evaluar f x, se evalúa primero el argumento x. (Las funciones están "ansiosas por evaluar sus argumentos".) Luego se evalúa la expresión de función f, que generalmente arroja un valor de función como fun x -> body. (Aquí, body aún no se ha evaluado, solo se ha evaluado que obtenemos un valor de función fun x -> body. Por ejemplo, f podría ser una expresión complicada que arroje tal valor de función como resultado.) Finalmente, el cuerpo de la función resultante se aplica al valor realmente calculado del argumento (es decir, el body se evalúa con x sustituido por el valor calculado del argumento).

Por esta razón, puede implementar "cita" en OCAML, si desea retrasar la evaluación de alguna expresión, solo poniéndola dentro del cuerpo de una expresión de función. Por ejemplo, si usted tiene calculado previamente f por let f = fun x->x+1 y ahora desea retrasar la evaluación de f 3, usted puede poner este f 3 en el cuerpo de una función:

let delay_f() = f 3;; 

AHORA LE 4 solamente cuando se evalúa delay_f(). Puede pasar el valor delay_f a otra función, y f 3 permanecerá sin evaluar hasta que alguien evalúe delay_f().

Cuestiones relacionadas