我理解如何在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
在这种情况下,它告诉我有无与伦比的模式。有没有办法满足它?
答案 0 :(得分:8)
如@ildjarn所述,这适用于所有模式。它们可以出现在match
子句(和function
中相似)的情况下,也出现在let
绑定函数的参数声明中,甚至出现在let
值中结合。
关键区别在于let
,您只想使用始终成功的完整模式。 match
或function
不需要这样做,因为有多个子句,所以如果第一个失败,匹配可以继续并尝试下一个。
例如,以下完整模式需要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
)。