为自定义集合定义 cons (::) 运算符

2024-03-15

我正在使用相当流行的FSharpx.Collections https://fsprojects.github.io/FSharpx.Collections/包,特别是非空列表 https://fsprojects.github.io/FSharpx.Collections/reference/fsharpx-collections-nonemptylist-1.html type.

该类型提供了NonEmptyList.cons功能,但我想使用::与常规操作符一样List, i.e. head :: tail. Since tail必须已经是NonEmptyList<'a>,不应该有任何冲突List's ::操作员。

但是,我似乎无法定义运算符。这:

let ( :: ) h t = NonEmptyList.cons h t

导致编译错误:

Unexpected symbol '::' in pattern. Expected ')' or other token.

我知道::与其他运算符不完全属于同一类别,但我不完全理解how。所以我或多或少随机尝试了一些事情,例如替换:: with op_cons等等,但没有成功。

我错过了什么吗?有办法做我想做的事吗?


根据 MSDN https://msdn.microsoft.com/en-us/library/dd233204.aspx, 冒号实际上不能用在操作符名称中。这似乎矛盾F# 规范 http://fsharp.org/specs/language-spec/3.1/FSharpSpec-3.1-working.docx来自 FSharp.org,我不确定那里发生了什么。但我们可以在 FSI 中验证:

> let ( >:> ) a b = a+b
Script.fsx(1,7): error FS0035: This construct is deprecated: ':' is not permitted as a character in operator names and is reserved for future use

如果你看how List<'T>被定义为 https://github.com/fsharp/fsharp/blob/0313094fa5d19fd871c83e7e45c35d1fad65daf9/src/fsharp/FSharp.Core/prim-types.fs#L3493,你会发现(::)实际上不是一个运算符,而是一个案例构造函数:

type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list

果然,您可以使用它作为构造函数名称来定义自己的 DU 类型:

> type A = 
>   | ( :: ) of string * int
>   | A of int
> 
> let a = "abc" :: 5

val a : A = Cons ("abc",5)

现在,奇怪的是,如果我尝试使用另一个看起来像运算符的名称作为 case 构造函数,我会收到此错误:

> type A = | ( |> ) of string * int
Script.fsx(1,14): error FS0053: Discriminated union cases and exception labels must be uppercase identifiers

意思就是(::)不知何故special(也是如此([]), 顺便一提)。

所以底线似乎是——不,你不能那样做。
但为什么你需要这样做呢?也许您可以选择一个更可接受的运算符名称,它仍然可以表达“cons”的语义 - 例如,(<+>)?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为自定义集合定义 cons (::) 运算符 的相关文章

随机推荐