【问题标题】:F# explicit match vs function syntaxF# 显式匹配 vs 函数语法
【发布时间】:2010-12-22 18:43:09
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: syntax f#


    【解决方案1】:

    它们在您的情况下做同样的事情——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) -> ....
    【解决方案2】:

    这两种语法是等价的。大多数程序员选择其中一个,然后始终如一地使用它。

    当函数在开始工作之前接受多个参数时,第一种语法仍然更具可读性。

    【讨论】:

      【解决方案3】:

      第二种语法的优点是,在 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]
      

      【讨论】:

        【解决方案4】:

        匹配版本称为“模式匹配表达式”。该函数版本称为“模式匹配函数”。在spec 的第 6.6.4 节中找到。

        使用一个而不是另一个是风格问题。当我需要定义一个只是匹配语句的函数时,我更喜欢只使用函数版本。

        【讨论】:

        【解决方案5】:

        函数版本是在匹配语句是整个函数并且函数只有一个参数(元组计为一个)的特殊情况下完整匹配语法的简写。如果你想有两个参数,那么你需要使用完全匹配语法*。你可以在以下两个函数的类型中看到这一点。

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

        【讨论】:

          【解决方案6】:

          为了完整起见,我刚到Expert FSharp的第321页:

          “注意,示例 12-2 使用了 function pattern-rules -> expression 的表达式形式。这等价于 (fun x -> match x with pattern-rules -> expression),并且作为定义直接在可区分联合上工作的函数的一种方式特别方便。”

          【讨论】:

            【解决方案7】:

            function 只允许一个参数但允许模式匹配,而 fun 是定义函数的更通用和灵活的方式。看这里:http://caml.inria.fr/pub/docs/manual-ocaml/expr.html

            【讨论】:

            • 你为什么只说 1 个参数而不是最后一个参数?可以有多个参数并使用“函数”。这是高阶函数解释吗?
            【解决方案8】:

            这是一个老问题,但我会抛出我的 0.02 美元。

            总的来说,我更喜欢match 版本,因为我来自“显式优于隐式”的 Python 世界。

            当然,如果需要参数的类型信息,则不能使用function 版本。

            OTOH 我喜欢 Stringer 提出的论点,所以我将开始在简单的 lambda 表达式中使用 function

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-12-22
              • 2015-07-12
              • 1970-01-01
              • 1970-01-01
              • 2010-10-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多