开发者

Guarantying assignment to a function's return value in OCaml

Coming to OCaml from Lisp, I find myself very confused about when functions return and when they don't. I miss my magic Quote! Thankfully, most of the time, OCaml ap开发者_开发百科pears to automagicly know when I want a function evaluated and when I don't. However, I frequently find myself trying to assign the return value of a function in a let expression, like the following.

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

but then ocamlc complains

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

Telling me that start and end are bound to Sys.time, not the return value of Sys.time.

Is this behavior I'm trying to get not OCamly? Do I want to be doing things another way? Am I just missing something completely obvious?


A function is evaluated when you apply it to an argument. I.e. when you do f, f never gets evaluated. When you do f x, f always gets evaluated. There's nothing magical about it.

As you correctly pointed out, Sys.time is a function (of type unit -> float) and let start = Sys.time just assigns that function to start.

To get the behavior you want simply do let start = Sys.time (), which applies the function Sys.time to the argument () (which is the only value of type unit).


You cannot call a function just by writing its name. If you just write a function's name, you're returning the function itself, not its return value. That error is telling you that the function takes a unit argument — i.e., you should write Sys.time () to actually apply the function and get the resulting float value.


To help people used to Lisp, I would say that there are only two evaluation rules in OCAML:

  • Delayed evaluation rule: A function value, such as fun x -> body, when not applied to any argument, will not be evaluated any further. (The evaluation of a function body is “delayed”.) Instead, the expression “body” is compiled into computer code. That computer code is the real “value” of the function expression, and the code will be run whenever the function is applied to an argument.
  • Eager evaluation rule: In evaluating f x, the argument x is evaluated first. (Functions are “eager to evaluate their arguments”.) Then the function expression f is evaluated, which generally yields a function value such as fun x -> body. (Here, body is not yet evaluated; only as much is evaluated that we get a function value fun x -> body. For example, f could be a complicated expression that yields such a function value as a result.) Finally, the body of the resulting function is applied to the actually computed value of the argument (i.e. the body is evaluated with x substituted by the computed value of the argument).

For this reason, you can implement "quote" in OCAML, if you want to delay the evaluation of some expression, only by putting it inside the body of a function expression. For example, if you have previously computed f by let f = fun x->x+1 and now you want to delay the evaluation of f 3, you can put this f 3 into the body of a function:

 let delay_f () = f 3;;

Now you will get 4 only when you evaluate delay_f (). You can pass the value delay_f to another function, and f 3 will stay unevaluated until somebody evaluates delay_f ().

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜