Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 具有可选元组列表的F模式匹配_F#_Pattern Matching - Fatal编程技术网

F# 具有可选元组列表的F模式匹配

F# 具有可选元组列表的F模式匹配,f#,pattern-matching,F#,Pattern Matching,我试图对可选的元组列表使用模式匹配,但尽管尝试了我所能想到的一切,我还是无法编写一个详尽的匹配表达式 我很难理解为什么F编译器坚持我在以下示例中的模式不是详尽无遗的 module Mapper.PatternMatchingOddity type A = A of string type B = B of string type ProblemType = ProblemType of (A * B) list option //Incomplete pattern matches on

我试图对可选的元组列表使用模式匹配,但尽管尝试了我所能想到的一切,我还是无法编写一个详尽的匹配表达式

我很难理解为什么F编译器坚持我在以下示例中的模式不是详尽无遗的

module Mapper.PatternMatchingOddity

type A = A of string
type B = B of string

type ProblemType = ProblemType of (A * B) list option

//Incomplete pattern matches on this expression. Some ([_;_]) may indicate a case...
let matchProblem = function
    |Some [(x:A,y:B)] -> []
    |Some ([_,_]) -> [] //rider says this rule will never be matched
    |None -> []

//same as before    
let matchProblem1 = function
    |Some [_,_] -> []
    |Some [] -> []
    //|Some _ -> []//this removes the warning but what is the case not covered by the previous two?
    |None -> []    

let matchProblem2 (input:ProblemType) =
    match input with //same as before
    |ProblemType (Some [(x:A,y:B)]) -> []
    |ProblemType None  -> []    

如何编写详尽的匹配,以及上面我遗漏了什么?你能给出一个输入的例子,它可以作为这些函数的一个有效参数,并在模式中穿行吗?

好问题!我认为许多以F开头的人都在努力解决列表、选项和元组的交互方式。让我先说:编译器是正确的。简单的回答是:您只匹配了多个单例列表。让我试着更深入地解释一下

您的类型本质上是“a*”b列表选项。在您的例子中,“a”和“b”本身就是一个使用字符串进行区分的单一案例。让我们稍微简化一下,看看如果我们孤立地查看类型的每个部分会发生什么,您可能已经知道这一点,但将其放到上下文中可能会有所帮助:

首先,您的类型是选项。这有两个值,无或一些“a”。要匹配某个选项,您可以执行以下操作

match o with 
| Some value -> value 
| None -> failwith "nothing"`
接下来,您的类型是一个列表。列表中的项目用分号分隔;。一个空列表是[],一个单项目列表是[x],多个项目是[x;y..]。要在列表的开头添加内容,请使用:。列表是一种特殊类型的区分并集,在其上匹配的语法模仿列表构造的语法:

match myList with
| [] -> "empty"
| [x] -> printfn "one item: %A" x
| [x; y] -> printfn "two items: %A, %A" x y
| x::rest -> printfn "more items, first one: %A" x
第三,列表类型本身就是元组类型。要解构或匹配元组类型,可以使用逗号,就像使用匹配x、y和1、2->它是1和2

结合所有这一切,我们必须在一个选项上进行匹配,然后是列表中间,然后是元组。例如,有些[]表示空列表,有些无表示缺少列表,有些[a,b]表示单例列表,有些a,b::rest表示包含一个或多个项的列表

现在我们已经掌握了理论,让我们看看是否可以处理您的代码。首先让我们看一下警告消息:

此表达式上的模式匹配不完整。有些[;u;]可能表示

这是正确的,代码中的项用分隔,表示元组,消息说Some[something;something]下划线表示任何内容,这是两个项的列表。但是添加它并没有多大帮助,因为列表仍然可以超过2

莱德说这条规则永远不会被匹配

Rider调用下面的FSC编译器服务是正确的。该行上方的规则是一些[x:A,y:B],此处不需要:A和:B,它们匹配任何具有元组的单例数组。有些[u,u]也会这样做,只是它不会捕获变量中的值

这将删除警告,但前两个警告未涵盖的情况是什么

它删除了警告,因为Some u表示Some with anything,正如u表示:它是anything的占位符。在本例中,它与空列表、2项列表、3项列表和n项列表匹配。在该示例中,您唯一匹配的是1项列表

你能举例说明一个可以被接受为有效参数的输入吗

对。您未匹配的有效输入是一些[]空列表,一些[A,B x;A 2,B 2]两项列表等

让我们举你的第一个例子。你有这个:

let matchProblem = function
    |Some [(x:A,y:B)] -> []  // matching a singleton list
    |Some ([_,_]) -> []   // matches a singleton list (will never match, see before)
    |None -> []  // matches None
以下是您可能需要的:

let notAProblemAnymore = function
    // first match all the 'Some' matches:
    | Some [] -> "empty"  // an empty list
    | Some [x,y] -> "singleton"  // a list with one item that is a tuple
    | Some [_,a;_,b] -> "2-item list"  // a list with two tuples, ignoring the first half of each tuple
    | Some ((x,y)::rest) -> "multi-item list" 
           // a list with at least one item, and 'rest' as the 
           // remaining list, which can be empty (but won't, 
           // here it has at least three items because of the previous matches)
    | None -> "Not a list at all" // matching 'None' for absence of a list
总而言之:您在匹配一个只有一个项的列表时,编译器抱怨您遗漏了其他长度的列表—空列表和包含多个项的列表


通常不必将选项与列表一起使用,因为空列表已经意味着缺少数据。因此,每当你发现自己在写“类型选项”列表时,考虑一下列表是否足够。这将使匹配更容易。

您正在努力,因为您的示例太“示例”

让我们将您的示例转换为更有意义的示例:检查输入,以便

如果为“无”,则打印“无”,否则: 如果有零元素,则打印“空” 如果只有一个元素,则打印“ony one element:…” 如果有两个元素,则打印“我们有两个元素:…” 如果有三个元素,则打印“有三个元素:…” 如果有三个以上的元素,则打印“哦,伙计,第一个元素是…,第二个元素是…,第三个元素是…,还有N个元素更多” 现在您可以看到,您的代码仅涵盖前3种情况。因此F编译器是正确的

要重写代码,请执行以下操作:

let matchProblem (ProblemType input) =
    match input with
    | None -> printfn "nothing"
    | Some [] -> ...
    | Some [(x, y)] -> ...
    | Some [(x1, y1); (x2, y2)] -> ...
    | Some [(x1, y1); (x2, y2); (x3, y3)] -> ...
    | Some (x1, y1) :: (x2, y2) :: (x3, y3) :: rest -> // access rest.Length to print the number of more elements
请注意,我在参数ProblemType输入上使用了模式匹配,以便以方便的方式提取输入。这使得后面的模式更简单

就我个人而言,当我学习F时,我不理解很多特性/语法
直到我在生产代码中使用它们。

。我希望我能不止一次投票。那个警告我读了一百万遍,但我的大脑坚持要解释“;”作为元组“*”中的分隔符,您的解释清楚地说明了我遗漏的要点。顺便说一句,我修改了代码,编译器对空列表、单项列表和多项列表都很满意,我认为我们的2项列表与单项列表完全相同,只是它允许访问元组元素。您关于列表是DU的特例的评论非常有趣,谢谢您的评论。@Dr很高兴我能为您服务!如果您有一个用例只需要零个或两个项目,不需要更多,不需要一个,那么您应该选择“a*”b选项样式类型。固定大小的列表最多有7个左右的项,最好以元组的形式构造。如果项目可以是可变的,请查看列表。谢谢。我的用例是正好两个项的零个或多个元组。问题中的代码是从实际代码简化而来的。我的用例是映射列表,因此是元组列表。我同意:这个选择在这里是多余的。空列表为我提供了所需的语义,尽管我想在删除选项之前确保我理解选项的使用是否与我的问题相关;