【发布时间】:2010-12-22 18:43:09
【问题描述】:
抱歉标题含糊,但这个问题的一部分是这两种语法样式的名称:
let foo1 x =
match x with
| 1 -> "one"
| _ -> "not one"
let foo2 = function
| 1 -> "one"
| _ -> "not one"
另一部分是两者之间有什么区别,我什么时候想使用其中一个?
【问题讨论】:
抱歉标题含糊,但这个问题的一部分是这两种语法样式的名称:
let foo1 x =
match x with
| 1 -> "one"
| _ -> "not one"
let foo2 = function
| 1 -> "one"
| _ -> "not one"
另一部分是两者之间有什么区别,我什么时候想使用其中一个?
【问题讨论】:
它们在您的情况下做同样的事情——function 关键字的作用类似于 fun 关键字(用于生成匿名 lambda)后跟 match 关键字的组合。
所以从技术上讲,这两者是相同的,只是多了一个fun:
let foo1 = fun x ->
match x with
| 1 -> "one"
| _ -> "not one"
let foo2 = function
| 1 -> "one"
| _ -> "not one"
【讨论】:
fun在技术上是根据function | _ -> ...定义的?
fun x y -> ... 将是fun x -> fun y -> ...,然后fun x -> ... 将是function | x -> ...。这就是为什么您可以在 fun 中进行模式匹配 - 例如fun (x::xs) -> ....
这两种语法是等价的。大多数程序员选择其中一个,然后始终如一地使用它。
当函数在开始工作之前接受多个参数时,第一种语法仍然更具可读性。
【讨论】:
第二种语法的优点是,在 lambda 中使用时,它可能更简洁易读。
List.map (fun x -> match x with | 1 -> "one" | _ -> "not one") [0;1;2;3;1]
对
List.map (function 1 -> "one" | _ -> "not one") [0;1;2;3;1]
【讨论】:
匹配版本称为“模式匹配表达式”。该函数版本称为“模式匹配函数”。在spec 的第 6.6.4 节中找到。
使用一个而不是另一个是风格问题。当我需要定义一个只是匹配语句的函数时,我更喜欢只使用函数版本。
【讨论】:
函数版本是在匹配语句是整个函数并且函数只有一个参数(元组计为一个)的特殊情况下完整匹配语法的简写。如果你想有两个参数,那么你需要使用完全匹配语法*。你可以在以下两个函数的类型中看到这一点。
//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 ??"
如您所见,匹配版本采用两个单独的参数,而函数版本采用单个元组参数。我对大多数单参数函数使用函数版本,因为我发现函数语法看起来更简洁。
*如果你真的想要,你可以让函数版本具有正确的类型签名,但在我看来它看起来很丑 - 请参阅下面的示例。
//val function_match_equivalent : string -> string -> string
let function_match_equivalent x y = (x, y) |> function
| "A", _ -> "Hello A"
| _, "B" -> "Hello B"
| _ -> "Hello ??"
【讨论】:
为了完整起见,我刚到Expert FSharp的第321页:
“注意,示例 12-2 使用了
function pattern-rules -> expression的表达式形式。这等价于(fun x -> match x with pattern-rules -> expression),并且作为定义直接在可区分联合上工作的函数的一种方式特别方便。”
【讨论】:
function 只允许一个参数但允许模式匹配,而 fun 是定义函数的更通用和灵活的方式。看这里:http://caml.inria.fr/pub/docs/manual-ocaml/expr.html
【讨论】:
这是一个老问题,但我会抛出我的 0.02 美元。
总的来说,我更喜欢match 版本,因为我来自“显式优于隐式”的 Python 世界。
当然,如果需要参数的类型信息,则不能使用function 版本。
OTOH 我喜欢 Stringer 提出的论点,所以我将开始在简单的 lambda 表达式中使用 function。
【讨论】: