2010-09-12 27 views
6

Đến với OCaml từ Lisp, tôi thấy mình rất bối rối khi các hàm trả về và khi chúng không. Tôi nhớ phép thuật của tôi Trích dẫn! Rất may, hầu hết thời gian, OCaml dường như tự động biết khi tôi muốn một chức năng được đánh giá và khi tôi không. Tuy nhiên, tôi thường thấy mình cố gán giá trị trả về của một hàm trong một biểu thức let, như sau.Đảm bảo chuyển nhượng cho giá trị trả về của hàm trong OCaml

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

nhưng sau đó ocamlc phàn nàn

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

Nói cho tôi mà bắt đầu và kết thúc chắc chắn sẽ Sys.time, không phải là giá trị trả về của Sys.time.

Hành vi này tôi đang cố gắng để không nhận được OCamly? Tôi có muốn làm mọi thứ theo cách khác không? Tôi chỉ thiếu một cái gì đó hoàn toàn rõ ràng?

Trả lời

10

Một hàm được đánh giá khi bạn áp dụng nó cho một đối số. I E. khi bạn làm f, f không bao giờ được đánh giá. Khi bạn làm f x, f luôn được đánh giá. Không có gì huyền diệu về nó.

Như bạn một cách chính xác chỉ ra, Sys.time là một chức năng (loại unit -> float) và let start = Sys.time chỉ gán chức năng đó để start.

Để nhận được hành vi bạn muốn chỉ cần thực hiện let start = Sys.time(), áp dụng hàm Sys.time cho đối số () (là giá trị duy nhất của loại unit).

3

Bạn không thể gọi hàm chỉ bằng cách viết tên của nó. Nếu bạn chỉ viết tên của hàm, bạn sẽ trả về chính hàm đó, chứ không phải giá trị trả về của hàm đó. Lỗi đó cho bạn biết rằng hàm nhận một đối số unit - tức là bạn nên viết Sys.time() để thực sự áp dụng hàm và nhận giá trị float kết quả.

0

Để giúp người sử dụng để Lisp, tôi sẽ nói rằng chỉ có hai quy tắc đánh giá trong OCAML:

  • Chậm quy tắc đánh giá: Một giá trị chức năng, chẳng hạn như fun x -> body, khi không áp dụng cho bất kỳ tranh cãi , sẽ không được đánh giá thêm nữa. (Việc đánh giá của một cơ quan chức năng là "trì hoãn".) Thay vào đó, biểu thức "cơ thể" được biên dịch thành mã máy tính. Mã máy tính đó là "giá trị" thực của biểu thức hàm và mã sẽ được chạy bất cứ khi nào hàm được áp dụng cho đối số.
  • Quy tắc đánh giá của người đánh cược: Khi đánh giá f x, đối số x được đánh giá trước tiên. (Chức năng là "mong muốn đánh giá đối số của họ".) Sau đó, biểu thức hàm f được đánh giá, thường mang lại giá trị hàm như fun x -> body. (Ở đây, body chưa được đánh giá; chỉ có nhiều được đánh giá là chúng ta nhận được một giá trị hàm fun x -> body. Ví dụ, f có thể là một biểu thức phức tạp mang lại giá trị hàm như vậy.) Cuối cùng, phần thân của hàm kết quả được áp dụng cho giá trị thực sự tính của đối số (ví dụ: body được đánh giá với x được thay thế bằng giá trị được tính của đối số).

Vì lý do này, bạn có thể thực hiện "báo giá" trong OCAML, nếu bạn muốn trì hoãn việc đánh giá một số biểu thức, chỉ bằng cách đặt nó vào bên trong nội dung của biểu thức hàm. Ví dụ, nếu trước đó bạn đã tính f bởi let f = fun x->x+1 và bây giờ bạn muốn trì hoãn việc đánh giá f 3, bạn có thể đặt này f 3 vào cơ thể của một hàm:

let delay_f() = f 3;; 

Bây giờ bạn sẽ nhận được 4 chỉ khi bạn đánh giá delay_f(). Bạn có thể chuyển giá trị delay_f đến một hàm khác và f 3 sẽ vẫn chưa được đánh giá cho đến khi ai đó đánh giá delay_f().

Các vấn đề liên quan