F#模式直接匹配let绑定

Nic*_*ckL 3 f# immutability pattern-matching guard-clause

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

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

    let value = 
        match arg with
        | 1 -> "value1"
        | 2 -> "value2"
        | _ -> failwith "key not found"
Run Code Online (Sandbox Code Playgroud)

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

    let key1 = 1
    let key2 = 2
    let value = 
        match arg with
        | key1 -> "value1"
        | key2 -> "value2"
        | _ -> failwith "key not found"
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*ian 6

只需使用大写字母和[<Literal>]它们,它按预期工作.

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

按约定,小写名称通常表示绑定到名称的通配符.


ege*_*ard 5

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

让我说我有

match arg with
| x when x = 0 -> "zero"
| y when y = 1 -> "one"
| _ -> "other"
Run Code Online (Sandbox Code Playgroud)

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

回到你遇到的问题:

let key1 = 1
let key2 = 2
let value = 
    match arg with
    | key1 -> "value1"
    | key2 -> "value2"
    | _ -> failwith "key not found"
Run Code Online (Sandbox Code Playgroud)

这不起作用的原因是因为在match表达式中,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"
Run Code Online (Sandbox Code Playgroud)

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

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

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