F#模式直接匹配let绑定

时间:2014-03-15 14:04:10

标签: f# pattern-matching immutability guard-clause

F#中是否可以直接模式匹配let绑定?

例如,编译时没有任何警告:

    let value = 
        match arg with
        | 1 -> "value1"
        | 2 -> "value2"
        | _ -> failwith "key not found"

以下内容提供了警告"此规则永远不会与匹配key2_的行匹配"

    let key1 = 1
    let key2 = 2
    let value = 
        match arg with
        | key1 -> "value1"
        | key2 -> "value2"
        | _ -> failwith "key not found"

这是因为虽然它们是不可变的,但let绑定与C#const变量不同吗?

4 个答案:

答案 0 :(得分:6)

只需使用大写字母和[<Literal>]它们就可以正常工作。

let [<Literal>] X = 0
let [<Literal>] Y = 1
let bla arg =
    match arg with
    | X -> "zero"
    | Y -> "one"
    | somethingelse -> somethingelse.ToString()

按惯例,小写名称通常表示绑定到名称的通配符。

答案 1 :(得分:5)

您收到该错误的原因是因为在匹配表达式的pattern子句中使用变量名时F#正在执行的操作。

假设我有

match arg with
| x when x = 0 -> "zero"
| y when y = 1 -> "one"
| _ -> "other"

我认为这是关键,尽管在匹配之前没有定义x或y,但这段代码仍然有用。这是因为x和y只是短代码,这使得编写匹配表达式更容易。在幕后,F#编译器实际上将x when x = 0转换为“let binding”,其中x绑定到arg。然后可以在x表达式和x = 0之后的表达式中使用->

回到你遇到的问题:

let key1 = 1
let key2 = 2
let value = 
    match arg with
    | key1 -> "value1"
    | key2 -> "value2"
    | _ -> failwith "key not found"

这不起作用的原因是因为在匹配表达式中,F#将key1重新绑定到arg的值,所以key1 -> "value1" is equivalent to如果arg1 = arg1则为“value1” 。第一个模式将始终匹配;因此,永远不会达到key2_

我不确定我的解释有多清楚,所以我还会提出第二种方法来解释发生的事情:

如果将匹配表达式转换为if-else,它将如下所示:

let key1 = 1
let key2 = 2

let value = 
    if let key1 = arg in arg = key1 then
        "value1"
    else if let key2 = arg in arg = key2 then
        "value2"
    else
        failwith "key not found"

(为什么是的,F#会让你把绑定扔进if表达式中)

此if / else表达式等同于您的匹配表达式。在这种形式中,很明显第一个条件总是评估为真。

我不会把它放在这里,但它可能有助于查看匹配表达式的代码引用。在我看到他们生成的抽象语法树看起来像什么之前,我并没有真正了解匹配表达式的内容。

答案 2 :(得分:2)

如果要在模式匹配的情况下匹配特定值,则只能使用文字。标识符表示绑定 - 即此模式匹配案例中的实际值将绑定到在本案范围内可见的标识符。

正如@DanielFabian所示,您可以定义自己的文字并为其命名。

如果你需要匹配的值在编译时是不知道的,你可以使用这样的守卫:

match arg with
| x when x = key1 -> "value1"
| x when x = key2 -> "value2"
| _ -> // etc

有关详细信息,请参阅MSDN article on pattern matching

答案 3 :(得分:1)

您尝试使用的代码引发了两个主要问题。

首先是模式匹配:

match arg with
| _ -> "value"

将arg与任何内容匹配,然后返回&#34;值&#34;

match arg with
| a -> "value"

将arg与任何内容匹配,调用它&#34; a&#34;,然后返回&#34;值&#34;。您可以将匹配视为拥有自己的小命名空间,a只存在于匹配中,而且只有匹配才能看到&#39;已经在其中命名的东西。

其次,如果要匹配一组预定义值,那么您可能希望使用有区别的联合。你可以这样定义一个:

type Keys=
| Key1
| Key2

然后像这样匹配:

match arg with
| Key1 -> "value1"
| Key2 -> "value2"

在这种情况下,它匹配Keys类型,而不是名为Key1或Key2的值。