F # 显式匹配与函数语法

很抱歉标题含糊不清,但这个问题的一部分是这两种语法样式的名称:

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


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

另一部分是这两者之间有什么区别,以及我什么时候想使用其中一个?

17784 次浏览

They do the same thing in your case -- the function keyword acts like a combination of the fun keyword (to produce an anonymous lambda) followed by the match keyword.

So technically these two are the same, with the addition of a fun:

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


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

The two syntaxes are equivalent. Most programmers choose one or the other and then use it consistently.

The first syntax remains more readable when the function accepts several arguments before starting to work.

The pro for the second syntax is that when used in a lambda, it could be a bit more terse and readable.

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]

The match version is called a "pattern matching expression". The function version is called a "pattern matching function". Found in section 6.6.4 of the spec.

Using one over the other is a matter of style. I prefer only using the function version when I need to define a function that is only a match statement.

The function version is a short hand for the full match syntax in the special case where the match statement is the entire function and the function only has a single argument (tuples count as one). If you want to have two arguments then you need to use the full match syntax*. You can see this in the types of the following two functions.

//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 ??"

As you can see match version takes two separate arguments whereas the function version takes a single tupled argument. I use the function version for most single argument functions since I find the function syntax looks cleaner.

*If you really wanted to you can get the function version to have the right type signature but it looks pretty ugly in my opinion - see example below.

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

Just for completeness sake, I just got to page 321 of Expert FSharp:

"Note, Listing 12-2 uses the expression form function pattern-rules -> expression. This is equivalent to (fun x -> match x with pattern-rules -> expression) and is especially convenient as a way to define functions working directly over discriminated unions."

function only allows for one argument but allows for pattern matching, while fun is the more general and flexible way to define a function. Take a look here: http://caml.inria.fr/pub/docs/manual-ocaml/expr.html

This is an old question but I will throw my $0.02.

In general I like better the match version since I come from the Python world where "explicit is better than implicit."

Of course if type information on the parameter is needed the function version cannot be used.

OTOH I like the argument made by Stringer so I will start to use function in simple lambdas.