为什么活动模式需要特殊语法?

Dan*_*iel 1 f# pattern-matching active-pattern

如果普通函数可以用作模式,则可以节省必须编写琐碎的活动模式,如

let (|NotEmpty|_|) s = Seq.tryPick Some s
Run Code Online (Sandbox Code Playgroud)

并且假设允许

let s = seq []
match s with
| Seq.tryPick Some -> ...
| _ -> //empty
Run Code Online (Sandbox Code Playgroud)

这将使函数更具可重用性,无需使用匹配的"模式化"函数:

let f x = if x then Some() else None
let (|F|_|) = f
Run Code Online (Sandbox Code Playgroud)

我知道活动模式可以被称为函数,因此可以通过定义模式来简化前面的示例.但是,放弃特殊模式语法简化了这一点.

特殊语法的原因是什么?

编辑

在下文中,活动模式会影响文字.

[<Literal>]
let X = 1
let (|X|_|) x = if x = 0 then Some() else None

match 0 with //returns true
| X -> true
| _ -> false
Run Code Online (Sandbox Code Playgroud)

为什么在模式中函数调用也不起作用?

编辑2

我发现了一个模棱两可的场景

let zero n = if n = 0 then Some() else None
match 0 with
| zero -> //function call or capture?
Run Code Online (Sandbox Code Playgroud)

在我看来,这清楚地说明了为什么活动模式必须以大写字母开头 - 它使意图更清晰并且使阴影(例如在我之前的示例中)更不可能.

Tom*_*cek 5

回答这个问题的一种方法是说活动模式(作为一种特殊的句法类别)可以使用相同的名称在表达式中构造值并在模式中解构它.

例如,假设我们使用一种类型Info来表示一些信息:

type Info = I of string * int
Run Code Online (Sandbox Code Playgroud)

您可以编写两个函数来构造和销毁此类型的值:

val constructInfo : string * int -> Info
val destructInfo  : Info -> string * int
Run Code Online (Sandbox Code Playgroud)

在这种情况下,这两个函数很容易实现,但有趣的是它们的类型签名是双重的.构造获取值并创建我们的(抽象)类型,销毁获取类型并返回单个值.

使用活动模式,我们可以使用相同的名称Info,用于这两个目的.这使得它与语言的其余部分保持一致 - 例如x::xs,(a, b)它们都是构造函数和模式.F#库对F#引用做了类似的事情(即Lambda类型的模式和构造函数都是如此Expr.

因此,我们可以定义一个函数和一个模式,而不是编写构造破坏函数:

let Info (a, b) = I (a, b)
let (|Info|) (I (a, b)) = (a, b)
Run Code Online (Sandbox Code Playgroud)

结果是,相同的语法Info(a, b)可以作为模式和表达式出现.