4

我的问题是受这个启发的: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

然后我得到一个错误:

错误

有没有一种很好的方法来修复它并且仍然在函数参数中使用模式匹配?如果不是,那他们为什么要创建这种奇怪的语法,总是会导致警告?

4

3 回答 3

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,所以是第一个的重复定义,因此是错误的。如果你想在某个联合类型上编写一个总函数,你应该使用模式匹配functionor 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
于 2014-01-28T12:42:41.670 回答
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
于 2014-01-28T12:50:32.900 回答
2

正如其他答案所说,最好的方法似乎是使用带有functionormatch关键字的模式匹配。
但是,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)

同样,不要在实际项目中盲目使用它,因为它似乎不可读。

进一步阅读:列表处理的类似方法

于 2014-01-28T19:15:40.870 回答