2012-08-23 40 views
6

Tôi hoàn toàn bối rối bằng cách quan sát hành vi này trong # mã F của tôi, đây được lấy từ một phiên tương tác:Tại sao ngoặc quan trọng trong F # khai báo kiểu

Microsoft (R) F# 2.0 Interactive build 4.0.40219.1 
Copyright (c) Microsoft Corporation. All Rights Reserved. 

For help type #help;; 

> type foo = Foo of (string * int);; 
    type foo = | Foo of (string * int) 

> let f = Foo ("bar",42);; 
    val f : foo = Foo ("bar", 42) 

> match f with Foo x -> x;; 
    val it : string * int = ("bar", 42) 

> type bar = Bar of string * int;; 
    type bar = | Bar of string * int 

> let b = Bar ("baz",21);; 
    val b : bar = Bar ("baz",21) 

> match b with Bar x -> x;; 
    match b with Bar x -> x;; 
    -------------^^^^^ 

stdin(7,14): error FS0019: This constructor is applied to 1 argument(s) but expects 2 
> 

Có vẻ như rõ ràng với tôi rằng mô hình kết hợp trên cả hai Foo và Bar với một biến duy nhất nên hợp lệ - vì vậy tôi đã tự hỏi nếu có ai biết lý do cho hành vi khủng khiếp này, hoặc nếu bạn thích tôi coi nó là một lỗi.

Cập nhật: Chỉ cần làm rõ, các loại báo cáo của các nhà thầu FooBar là:

> Foo;; 
val it : string * int -> foo = <fun:[email protected]> 
> Bar;; 
val it : string * int -> bar = <fun:[email protected]> 

Vì vậy, chắc chắn, họ phải chấp nhận cùng một tập các mẫu hợp lệ

Trả lời

6

Tôi đồng ý điều này có vẻ khá gây nhầm lẫn. Như pad giải thích, sự khác biệt giữa hai khai báo không chỉ là cú pháp - bạn đang thực sự xác định các trường hợp nghiệp đoàn phân biệt đối xử bao gồm các kiểu khác nhau.

  • Trong trường hợp Foo, trường hợp có chứa một phần tử kiểu int * string
  • Trong trường hợp Bar, trường hợp có chứa hai phần tử kiểu intstring

Hai tùy chọn là rất giống nhau, nhưng chúng thực sự khác nhau. Bạn có thể thấy rằng nếu bạn nhìn vào the type definitions in the F# specification. Dưới đây là các bit mô tả định nghĩa kiểu của công đoàn phân biệt đối xử:

đoàn-type-defn: =
    type-name '=' đoàn-type-trường hợp type-mở rộng-yếu tố chọn

loại hình công đoàn: =
    '|' chọn union-type-case '|' ...'|' đoàn kiểu hợp cụ thể

đoàn kiểu hợp cụ thể: =
    thuộc tính opt   đoàn kiểu hợp dữ liệu

đoàn-type-trường dữ liệu: =
    ident                                                                     - vô trường hợp đoàn
    ident loại * ... * Loại           - n trường hợp công đoàn ary

Lưu ý rằng "trường hợp công đoàn n-ary" bao gồm nhiều phần tử (type * ... * type). Một loại được định nghĩa như sau (không đáng ngạc nhiên, nó có thể là một tuple):

loại: =
    (loại)
    loại -> gõ               - loại chức năng
    loại * ... * loại       - tuple loại
    ...                                                 - rất nhiều loại khác

Tôi không biết tại sao union-type-case-data không chỉ sử dụng trường hợp công đoàn đơn nhất (thay vì n-ary) và luôn coi các phần tử là bộ dữ liệu. Tôi nghĩ điều đó sẽ có ý nghĩa hoàn hảo, nhưng nó có thể là thứ mà F # được thừa kế từ OCaml hoặc ML. Tuy nhiên, ít nhất là đặc điểm kỹ thuật giải thích điều này!

Trong thực tế, tôi cho rằng đặc điểm kỹ thuật hơi mơ hồ, vì bạn có thể coi Foo of int * int là cả trường hợp công đoàn n-ary và trường hợp đơn nhất với một bộ túp (nhưng không có loại lợ (type)).

+0

Cảm ơn bạn đã trả lời rất kỹ lưỡng, thậm chí chỉ ra phần có liên quan của đặc tả ngôn ngữ! Nhưng tôi sợ rằng bây giờ tôi coi nó là một quái vật nghiêm trọng hơn, bây giờ nó đã được cố ý! :-) – plc

+1

@plc - Tôi dự đoán rằng lý do cho sự khác biệt là kiểm soát ranh giới giữa các ngôn ngữ khác như C#. Trong trường hợp đó, bạn có thể quan tâm nếu bạn cần tạo một thể hiện DU bằng cách truyền vào một bộ dựng sẵn hoặc bằng cách truyền vào các thành phần riêng lẻ. – kvb

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