我的问题受到这个问题的启发:link
这是一段代码:
type A =
| X of int * int
| Y of string
let f (A.X(a, b)) = a + b
它有效但有警告:
有道理;我和Y没有匹配。
但如果我添加一行
let f (A.Y(s)) = 10
然后我收到错误:
有没有一种很好的方法来修复它并仍然在函数参数中使用模式匹配?如果没有,那么为什么他们会创建这种奇怪的语法,这总会导致警告?
答案 0 :(得分:8)
您需要对参数进行模式匹配:
let f = function
| X(a, b) -> a + b
| Y(_) -> 10
定义时
let f (A.X(a, b)) = a + b
f
的类型为A -> int
,而非A.X -> int
。它没有为A.Y
的实例值定义,因此您会得到不完整的匹配警告。
您对f
的第二个定义也有类型A -> int
,因此是第一个的重复定义,因此是错误。如果要在某种联合类型上编写一个总函数,则应使用与function
或match
匹配的模式。
编辑:在回复评论时,如果您想要同时匹配多个参数,可以使用match
例如:
let f a1 a2 =
match (a1, a2) with
| (X(a, b), X(a', b')) -> a + b
| (X(a, b), Y(s)) -> a + 10
| (Y(s), X(a, b)) -> 10
| (Y(s), Y(s')) -> 20
答案 1 :(得分:4)
某些模式匹配可以是完整的,并且可能在函数参数中有用,例如fst
的这个定义是与元组匹配的模式,并且对于所有2个元组都是完整的。
let fst (a,_) = a
其他一些例子:
type Container = Container of string
let unwrap (Container(v)) = v
type Person = { Name:string; Age:int }
let getName {Name=name} = name
答案 2 :(得分:2)
正如其他答案所说,最好的方法似乎是使用function
或match
个关键字进行模式匹配。
但是,F#的原生模式匹配本身就是非常强大的功能。考虑下面的代码,但是我并不主张在现实世界的项目中使用它。我宁愿将它用作练习以更好地理解语言。
let f ((A.X(a, b), _ ) | (A.Y(_), (a, b))) = a + b
// usage
let x1 = f(A.X(10, 42), (100, 1)) // x1 = 52
let x2 = f(A.Y("foo"), (100, 1)) // x2 = 101
这里发生了什么?
A.X
中提取或作为单独的参数提供; A.Y(string)
时,我们仍然需要将一些加起来。A.X(int, int)
的某个含义值,则忽略回退值。然而,不要盲目地在现实世界的项目中使用它,因为它似乎不可读。