对活动模式感到困惑

时间:2012-10-04 23:08:22

标签: .net f# functional-programming

我理解如何在F#中定义和使用活动模式,包括部分活动模式,以及可用的不同类型的模式。 E.g。

let (|Big|Small|) animal = if animal.IsBig then Big(animal) else Small(animal)
let f = function | Big(_) -> "big" |Small(_) -> "small

但是,我对在let绑定,参数和其他地方使用活动模式和有区别的联盟感到困惑。例如,MSDN具有以下代码:

let GetSubstring1 (Slice(p0, p1, text)) = 
    printfn "Data begins at %d and ends at %d in string %s" p0 p1 text
    text.[p0..p1]

让我感到困惑。

具体问题。假设我有歧视的联盟,

type Union = A of int * int | B of int

我可以以某种方式创建一个只接受Union.A的函数,例如

let f (A(a, b)) = a + b

在这种情况下,它告诉我有无与伦比的模式。有没有办法满足它?

1 个答案:

答案 0 :(得分:8)

如@ildjarn所述,这适用于所有模式。它们可以出现在match子句(和function中相似)的情况下,也出现在let绑定函数的参数声明中,甚至出现在let值中结合。

关键区别在于let,您只想使用始终成功的完整模式。 matchfunction不需要这样做,因为有多个子句,所以如果第一个失败,匹配可以继续并尝试下一个。

例如,以下完整模式需要int并将其作为string返回:

let (|AsString|) (n:int) = n.ToString()

以下是一些如何使用它的方法:

let (AsString s) = 42         // Defines a value 's' of type string
match 3 with AsString s -> s  // Returns a value "3" of type string
let convert (AsString s) = s  // Defines a function 'int -> string'
let convert = function AsString s -> s  // Same as the previous line

编辑:要回答第二个问题,如果您使用带有不完整模式的let(即只接受一个受歧视联盟的案例)然后你得到一个编译器警告,代码可能在运行时失败(如果你用其他有区别的联合案例调用它):

let f (A(a, b)) = a + b      // This gives compile-time warning
f (B 42)                     // This will fail at runtime 

如果您需要定义仅适用于其中一种情况的函数,则需要定义一个单独的类型。

type AInfo = int * int 
type Union = A of AInfo | B of int  

然后你可以编写一个只需要AInfo的函数(但你仍然可以在两个选项代表有效输入的地方使用Union)。