繁体   English   中英

F#模式直接与let绑定匹配

[英]F# pattern match directly against let binding

在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变量?

只需使用大写字母并[<Literal>] ,它就会按预期工作。

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

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

出现该错误的原因是由于在匹配表达式的pattern子句中使用变量名称时F#正在做什么。

假设我有

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

我认为在这里要注意的关键是,尽管没有在比赛之前定义x或y,但是此代码仍然可以工作。 这是因为x和y只是短代码,这使得编写匹配表达式更加容易。 在后台,F#编译器实际上是x when x = 0x 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_

我不确定我的解释是否清楚,因此我还将介绍另一种方法来解释发生的情况:

如果将match表达式转换为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#将让您将let绑定放入if表达式中)

该if / else表达式与您的match表达式等效。 通过这种形式,很明显第一个条件将始终为true。

我不会在这里放它,但是它可能有助于查看match表达式的代码引用。 直到看到匹配表达式生成的抽象语法树,我才真正知道匹配表达式的情况。

如果要在模式匹配情况下与特定值匹配,则只能使用文字。 标识符意味着绑定-即在这种模式匹配情况下的实际值将绑定到在这种情况下可见的标识符。

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

如果在编译时未知需要匹配的值,则可以使用如下防护措施:

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

有关更多详细信息,请参见MSDN上有关模式匹配的文章

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

首先模式匹配:

match arg with
| _ -> "value"

将arg与任何东西匹配,然后返回“值”

match arg with
| a -> "value"

将arg与任何东西匹配,将其称为“ a”,然后返回“ value”。 您可以想到该匹配项具有自己的小命名空间,该匹配项仅存在于匹配项中,并且该匹配项仅“看到”其中已命名的内容。

其次,如果要匹配一组预定义的值,则可能要使用区分的并集。 您可以这样定义:

type Keys=
| Key1
| Key2

然后像这样匹配:

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM