受歧视工会中的咖喱争论
Curried Arguments in Discriminated Unions
我有这样一个受歧视的工会:
type A = |B | C of int*A
我必须像这样进行模式匹配(括号似乎是必需的):
match x with
| B -> printfn "B"
| C (i,a) -> printfn "%A, %A" i a
有没有一种方法可以像这样与活动模式相匹配:
match x with
| B -> printfn "B"
| C i a -> printfn "%A, %A" i a
如果不是,为什么 F# 设计成这种与 curried 参数的匹配不起作用,而是强制您使用元组?
编辑:这是受 F# 列表的启发,您可以在其中使用 h::t
而无需任何元组或类似的东西。源代码如下:
type List<'T> =
| ([]) : 'T list
| (::) : Head: 'T * Tail: 'T list -> 'T list
您的已区分联合中的案例 C
具有元组类型 (int * A)
的值。
模式匹配的 (i,a)
部分不是参数,它是将 i
匹配到 int
部分,将 a
匹配到 A
部分。
您同样可以匹配 C x
,而 x
将包含 (int * A)
.
的元组
我认为检查柯里化函数和活动模式的定义会让您明白这一点。
柯里化函数:
一个接受多个参数但允许一次传递一个参数的函数,以便 return 一个功能相同但只接受一个较少参数的函数。示例:
let add a b = a + b
//val add : a:int -> b:int -> int
let add5 = add 5
//val add5 : (int -> int)
活动模式:
一种应用模式匹配的方法,可以使用解析或其他复杂逻辑来完成匹配。接受一个参数和 returns 解析的结果。所以输入->单return参数.
//Example taken from https://fsharpforfunandprofit.com/posts/convenience-active-patterns/
let (|Int|_|) str =
match System.Int32.TryParse(str) with
| (true,int) -> Some(int)
| _ -> None
val ( |Int|_| ) : str:string -> int option
由于柯里化函数的全部意义在于能够部分应用函数,因此当应用于活动模式的结果时,这个概念根本没有意义。
换句话说,活动模式的结果不能是 "curried",因为您只能柯里化函数,而活动模式的结果是不是函数的数据。在您的示例中,'C (i,a)' 正在定义活动模式案例的 return 类型,而不是函数调用。
不能将空格作为绑定模式之间的分隔符,因为联合案例和活动模式都不支持这一点。根据 F# spec 的语法:
6.9.8 评估联合案例
Case(e1,…,en)
7.2.3 活动模式
(|CaseName|) arg1 ... argn inp
(|CaseName|_|) arg1 ... argn inp
所以它必然是联合案例的一个元组参数;香蕉函数的 n+1 个参数,其中 n 个参数是参数。只有最后一个参数绑定到模式。考虑:
type X = B | C
let (|C|) a b = C (a, b)
let i = 42
match C with
| B -> printfn "B"
| C i a -> printfn "%A, %A" i a // prints 42, (42, C)
我有这样一个受歧视的工会:
type A = |B | C of int*A
我必须像这样进行模式匹配(括号似乎是必需的):
match x with
| B -> printfn "B"
| C (i,a) -> printfn "%A, %A" i a
有没有一种方法可以像这样与活动模式相匹配:
match x with
| B -> printfn "B"
| C i a -> printfn "%A, %A" i a
如果不是,为什么 F# 设计成这种与 curried 参数的匹配不起作用,而是强制您使用元组?
编辑:这是受 F# 列表的启发,您可以在其中使用 h::t
而无需任何元组或类似的东西。源代码如下:
type List<'T> =
| ([]) : 'T list
| (::) : Head: 'T * Tail: 'T list -> 'T list
您的已区分联合中的案例 C
具有元组类型 (int * A)
的值。
模式匹配的 (i,a)
部分不是参数,它是将 i
匹配到 int
部分,将 a
匹配到 A
部分。
您同样可以匹配 C x
,而 x
将包含 (int * A)
.
我认为检查柯里化函数和活动模式的定义会让您明白这一点。
柯里化函数: 一个接受多个参数但允许一次传递一个参数的函数,以便 return 一个功能相同但只接受一个较少参数的函数。示例:
let add a b = a + b
//val add : a:int -> b:int -> int
let add5 = add 5
//val add5 : (int -> int)
活动模式: 一种应用模式匹配的方法,可以使用解析或其他复杂逻辑来完成匹配。接受一个参数和 returns 解析的结果。所以输入->单return参数.
//Example taken from https://fsharpforfunandprofit.com/posts/convenience-active-patterns/
let (|Int|_|) str =
match System.Int32.TryParse(str) with
| (true,int) -> Some(int)
| _ -> None
val ( |Int|_| ) : str:string -> int option
由于柯里化函数的全部意义在于能够部分应用函数,因此当应用于活动模式的结果时,这个概念根本没有意义。
换句话说,活动模式的结果不能是 "curried",因为您只能柯里化函数,而活动模式的结果是不是函数的数据。在您的示例中,'C (i,a)' 正在定义活动模式案例的 return 类型,而不是函数调用。
不能将空格作为绑定模式之间的分隔符,因为联合案例和活动模式都不支持这一点。根据 F# spec 的语法:
6.9.8 评估联合案例
Case(e1,…,en)
7.2.3 活动模式
(|CaseName|) arg1 ... argn inp
(|CaseName|_|) arg1 ... argn inp
所以它必然是联合案例的一个元组参数;香蕉函数的 n+1 个参数,其中 n 个参数是参数。只有最后一个参数绑定到模式。考虑:
type X = B | C
let (|C|) a b = C (a, b)
let i = 42
match C with
| B -> printfn "B"
| C i a -> printfn "%A, %A" i a // prints 42, (42, C)