F # đối sánh rõ ràng với cú pháp hàm


87

Xin lỗi về tiêu đề mơ hồ, nhưng một phần của câu hỏi này là hai kiểu cú pháp này được gọi là gì:

let foo1 x = 
    match x with
    | 1 -> "one"
    | _ -> "not one"

let foo2 = function 
    | 1 -> "one" 
    | _ -> "not one"

Phần khác là có sự khác biệt nào giữa hai cái này, và khi nào tôi muốn sử dụng cái này hay cái kia?

Câu trả lời:


56

Phiên bản đối sánh được gọi là "biểu thức đối sánh mẫu". Phiên bản chức năng được gọi là "chức năng so khớp mẫu". Tìm thấy trong phần 6.6.4 của thông số kỹ thuật .

Sử dụng cái này hơn cái kia là một vấn đề của phong cách. Tôi chỉ thích sử dụng phiên bản hàm khi tôi cần xác định một hàm chỉ là một câu lệnh so khớp.


Cảm ơn bạn. Mặc dù Lập trình Chức năng Sử dụng F # nói rằng việc sử dụng từ khóa function cho thấy đó là một chức năng so khớp mẫu, nhưng câu trả lời này và OP làm rõ một thời điểm não bị kẹt.
octopusgrabbus

Liên kết dường như bị hỏng.
MattMS

83

Ưu điểm cho cú pháp thứ hai là khi được sử dụng trong lambda, nó có thể ngắn gọn và dễ đọc hơn một chút.

List.map (fun x -> match x with | 1 -> "one" | _ -> "not one") [0;1;2;3;1]

vs

List.map (function 1 -> "one" | _ -> "not one") [0;1;2;3;1]

23

Phiên bản hàm là cách viết tắt của cú pháp đối sánh đầy đủ trong trường hợp đặc biệt khi câu lệnh đối sánh là toàn bộ hàm và hàm chỉ có một đối số duy nhất (số bộ giá trị là một). Nếu bạn muốn có hai đối số thì bạn cần sử dụng cú pháp đối sánh đầy đủ *. Bạn có thể thấy điều này trong các kiểu của hai hàm sau.

//val match_test : string -> string -> string
let match_test x y = match x, y with
                        | "A", _ -> "Hello A"
                        | _, "B" -> "Hello B"
                        | _ -> "Hello ??"

//val function_test : string * string -> string                   
let function_test = function
                        | "A", _ -> "Hello A"
                        | _, "B" -> "Hello B"
                        | _ -> "Hello ??"

Như bạn có thể thấy, phiên bản đối sánh có hai đối số riêng biệt trong khi phiên bản hàm có một đối số được nhóm đơn. Tôi sử dụng phiên bản hàm cho hầu hết các hàm đối số đơn lẻ vì tôi thấy cú pháp hàm trông gọn gàng hơn.

* Nếu bạn thực sự muốn, bạn có thể lấy phiên bản hàm để có chữ ký đúng kiểu nhưng theo ý kiến ​​của tôi thì nó trông khá xấu - xem ví dụ bên dưới.

//val function_match_equivalent : string -> string -> string
let function_match_equivalent x y = (x, y) |> function
                                                | "A", _ -> "Hello A"
                                                | _, "B" -> "Hello B"
                                                | _ -> "Hello ??"

12

Họ làm điều tương tự trong trường hợp của bạn - functiontừ khóa hoạt động giống như sự kết hợp của funtừ khóa (để tạo ra một lambda ẩn danh) theo sau là matchtừ khóa.

Vì vậy, về mặt kỹ thuật, cả hai đều giống nhau, với việc bổ sung fun:

let foo1 = fun x ->
    match x with
    | 1 -> "one"
    | _ -> "not one"

let foo2 = function
    | 1 -> "one"
    | _ -> "not one"

1
Nó không thực sự là ngược lại - tức funlà được định nghĩa về mặt kỹ thuật function | _ -> ...?
Pavel Minaev

1
Cụ thể, fun x y -> ...sẽ là fun x -> fun y -> ..., và sau đó fun x -> ...sẽ là function | x -> .... Đó là lý do tại sao bạn có thể thực hiện đối sánh mẫu trong fun- ví dụ fun (x::xs) -> ....
Pavel Minaev

10

Chỉ vì mục đích hoàn chỉnh, tôi vừa mới đến trang 321 của Expert FSharp :

"Lưu ý, Liệt kê 12-2 sử dụng dạng biểu thức function pattern-rules -> expression. Điều này tương đương (fun x -> match x with pattern-rules -> expression)và đặc biệt thuận tiện như một cách để xác định các hàm hoạt động trực tiếp trên các liên kết bị phân biệt đối xử."


6

hàm chỉ cho phép một đối số nhưng cho phép đối sánh mẫu, trong khi fun là cách tổng quát và linh hoạt hơn để xác định một hàm. Hãy xem tại đây: http://caml.inria.fr/pub/docs/manual-ocaml/expr.html


tại sao bạn chỉ nói 1 đối số thay vì chỉ đối số cuối cùng? có thể có nhiều hơn 1 đối số và sử dụng "function". Đây có phải là một cách diễn giải hàm bậc cao hơn không?
symbiont

4

Hai cú pháp là tương đương. Hầu hết các lập trình viên chọn cái này hay cái kia và sau đó sử dụng nó một cách nhất quán.

Cú pháp đầu tiên vẫn dễ đọc hơn khi hàm chấp nhận một số đối số trước khi bắt đầu hoạt động.


2

Đây là một câu hỏi cũ nhưng tôi sẽ ném 0,02 đô la của mình.

Nói chung, tôi thích matchphiên bản tốt hơn vì tôi đến từ thế giới Python, nơi "rõ ràng tốt hơn ẩn."

Tất nhiên, nếu cần nhập thông tin về tham số, functionphiên bản không thể được sử dụng.

OTOH Tôi thích lập luận được đưa ra bởi Stringervậy tôi sẽ bắt đầu sử dụng functiontrong lambdas đơn giản.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.