2013-08-23 29 views
6

Xem xét lambda vô nghĩa sau đây:F # mô hình kết hợp kỳ quặc

function 
| [] -> "Empty list" 
| hd::tl -> "Not so empty list" 

này hoạt động tốt. Bây giờ tôi viết lại nó như sau:

function 
| [] -> "Empty list" 
| hd::tl & l -> "Not so empty list" 

Một lần nữa, vì những lý do vô nghĩa (và tôi biết rằng tôi có thể đạt được hiệu quả tương tự bằng cách sử dụng as thay vì &, nhưng tất cả điều này đã làm với một vấn đề mã golf đó là không thích hợp với câu hỏi này). Bây giờ trình biên dịch F # cho tôi biết:

cảnh báo FS0025: Mẫu không hoàn chỉnh khớp với biểu thức này. Đối với ví dụ , giá trị '[]' có thể cho biết một trường hợp không được bao gồm trong các mẫu .

Điều này không có ý nghĩa gì - tôi xử lý rõ ràng trường hợp [] trong quy tắc đầu tiên. Tôi không thấy điều gì đã thay đổi từ hàm đầu tiên sang hàm thứ hai liên quan đến []; quy tắc thứ hai của cả hai chức năng sẽ không khớp với quy tắc thứ hai mà chỉ có chức năng thứ hai đưa ra cảnh báo. Tất cả những gì tôi đã làm là thêm một mẫu bổ sung khớp với mọi thứ.

Tất nhiên, việc gọi hàm thứ hai có danh sách trống sẽ thành công.

Có lý do chính đáng nào tại sao cảnh báo này xảy ra hay không, việc xác thực mẫu F # có đơn giản là có một số câu hỏi không? Tôi có thể thấy có một số trường hợp như thế này khi các mẫu nâng cao hơn được sử dụng, nhưng điều này có vẻ như là một mô hình khá cơ bản. Ngay cả khi vấn đề không thể được giải quyết nói chung, có vẻ như loại trường hợp này sẽ đủ phổ biến để có được sự xử lý đặc biệt trong trình biên dịch.

+1

tôi chưa bao giờ thấy '&' được sử dụng theo cách đó. Bạn có thể liên kết đến một số tài liệu về những gì không? – JaredPar

+3

@JaredPar - xem VÀ mẫu tại đây http://msdn.microsoft.com/en-us/library/dd547125.aspx. Về cơ bản nó có nghĩa là bạn có thể nhận được đầu, đuôi và toàn bộ danh sách trong một đi –

Trả lời

6

Tôi nghĩ trình biên dịch F # đang được thực hiện trong trường hợp này.

Cuối cùng, nguyên tắc thứ hai có thể được diễn tả như một hạn chế trong danh sách đầu vào xs:

xs = hd :: tl && xs = l 

F # biên dịch dường như không khám phá && ràng buộc. Điều này là hợp lý vì các ràng buộc có thể tùy ý phức tạp và việc sử dụng & là khá hiếm.

Chúng tôi có một vấn đề tương tự với partial active patterns:

let (|Empty|_|) = function 
    | [] -> Some() 
    | _ -> None 

let (|NonEmpty|_|) = function 
    | _ :: _ -> Some() 
    | _ -> None 

// warning FS0025 
let f = function 
    | Empty -> "Empty list" 
    | NonEmpty -> "Not so empty list" 

Để khắc phục vấn đề này, bạn có thể:

  • Sử dụng as thay vì &, đó là thích hợp hơn vì l chỉ là một ràng buộc.
  • Thêm mẫu ký tự đại diện vào cuối để loại bỏ cảnh báo. Tôi thường viết

    let f = 
        function 
        | hd::tl & l -> "Not so empty list" 
        | _ -> "Empty list" 
    
  • Ngăn chặn cảnh báo bằng cách sử dụng nowarn "25".

+0

Vâng, tôi đã nhìn thấy cảnh báo với các mô hình hoạt động từng phần trước đây. Đó là một trong những thực sự làm cho tinh thần mặc dù, nhìn thấy như là các mô hình hoạt động được biên dịch chức năng và không macro và do đó trình biên dịch không thể xác minh tĩnh đầy đủ của các trận đấu. Bây giờ nếu có một số cách để xác định một mẫu đang hoạt động với từ khóa 'inline' (tôi đã thử), đó có thể là một câu chuyện khác. – luksan

+1

Bạn có thể sử dụng 'inline' với các mẫu đang hoạt động:' let inline (| Empty | _ |) xs = match xs với [] -> Some() | _ -> Không có gì, nhưng cảnh báo vẫn còn đó. – pad

+0

Tôi đoán bạn nói đúng. Mặc dù nếu tôi làm '<@@ function [] -> Some() | _ -> Không có @@> 'Tôi thấy rằng AST cho biểu thức khớp chỉ là một if/else, vì vậy thông tin mẫu vẫn bị mất. – luksan

4

Tôi đoán bạn đã tìm thấy một trường hợp khác (ngoài các mệnh đề when và mô hình hoạt động một phần) trong đó quy trình quyết định của trình biên dịch không đủ mạnh. (Đó là lý do tại sao thông báo cảnh báo cho biết có thể cho biết :-)).

Nếu bạn muốn có chức năng tương tự mà không có cảnh báo, bạn có thể sử dụng mẫu hoạt động hoàn chỉnh như thế này (nhưng thực tế, đối với danh sách, tôi có thể chỉ cần đi với _ cho trường hợp danh sách trống như @pad đề xuất) :

let (|Empty|NonEmpty|) l = 
    match l with [] -> Empty | x::xs -> NonEmpty(x, xs, l) 

let foo = function 
    | Empty -> 0 
    | NonEmpty(x, xs, l) -> 1 
+0

Nó nói "có thể chỉ ra", nhưng nó cũng nói "không đầy đủ" thay vì "có thể không đầy đủ", do đó, nó là hơi mơ hồ. – luksan

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