2013-10-28 22 views
5

Chúng ta hãy cùng giá trị hàm đơn giản f1:Tại sao giá trị hàm tổng quát rõ ràng ràng buộc khác với giá trị tương tự không chung chung?

let f1 = printfn "*bind f1*"; fun() -> printfn "f1()" 

f1 với phím tắt trong FSI như

*bind f1* 
val f1 : (unit -> unit) 

và, được gọi, cư xử như mong đợi

>() |> f1 |> f1;; 
f1() 
f1() 
val it : unit =() 

Bây giờ chúng ta hãy xem một chức năng tương tự giá trị, nhưng được thực hiện một cách rõ ràng chung f2<'a>:

let f2<'a> = printfn "*bind f2*"; fun() -> printfn "f2()" 

f2 liên kết trong FSI như

val f2<'a> : (unit -> unit) 

mà không cần bất kỳ *bind f2* sản lượng nào, nhưng sau đó, được gọi, kết quả đầu ra nó trên mỗi f2 gọi:

>() |> f2 |> f2;; 
*bind f2* 
f2() 
*bind f2* 
f2() 
val it : unit =() 

Câu hỏi của tôi là: những gì có thể là nguyên nhân cho sự chênh lệch quan sát như vậy?

+1

f2 là hàm kiểu (10.2.3 trong f # spec) – desco

+0

@desco: Cảm ơn bạn, Vladimir! Nếu bạn không quan tâm để đưa điều này vào một câu trả lời tôi sẽ rất vui khi chấp nhận nó. –

Trả lời

4

F # không thường là cho phép tạo các giá trị chung vì những hạn chế về giá trị "" này (nghĩa là bạn không thể tạo giá trị cú pháp chung chung, ngay cả khi nó là mã trả về hàm) . Vì vậy, không nên cho phép f2 của bạn, nhưng ...

Quy tắc này có một ngoại lệ duy nhất - thường hữu ích khi có giá trị chung như List.empty và vì vậy nếu bạn khai báo giá trị với đối số chung loại rõ ràng, thực tế là được biên dịch thành một hàm trả về kết quả.

Đó chính xác là những gì xảy ra trong ví dụ của bạn:

let f2<'a> = printfn "*bind f2*"; fun() -> printfn "f2()" 

đây, f2 là một giá trị chung (mặc dù nó không thực sự sử dụng các đối số kiểu bất cứ nơi nào), nhưng nó có một cuộc tranh cãi kiểu generic rõ ràng và do đó nó thực sự biên dịch thành một phương pháp đó được gọi là mỗi lần f2 được truy cập và nó trả về kết quả (chức năng unit -> unit)

tôi không thể tìm thấy bất kỳ lời giải thích rõ ràng cho điều này trong các đặc điểm kỹ thuật, nhưng có một good MSDN article (xem "Trường hợp 4 ") và cũng là một blog by former F# team member.

2

Tomas đúng, như thường lệ. Lưu ý rằng bạn có thể tạo hàm chung hoạt động như f1, nhưng bạn phải sử dụng loại chung danh nghĩa làm bộ nhớ cache loại:

type private Container<'a>() = 
    static member val f2 : unit -> unit = printfn "*bind f2*"; fun() -> printfn "f2()" 

let f2<'a>() = Container<'a>.f2() 
Các vấn đề liên quan