我使用的是相当受欢迎的FSharpx.Collections软件包,特别是NonEmptyList类型。
此类型提供NonEmptyList.cons
功能,但我希望::
运算符与常规List
一样使用,即head :: tail
。由于tail
必须已经是NonEmptyList<'a>
,因此不应与List
的{{1}}运营商发生任何冲突。
然而,似乎我无法定义运算符。这样:
::
导致编译错误:
let ( :: ) h t = NonEmptyList.cons h t
我知道Unexpected symbol '::' in pattern. Expected ')' or other token.
与其他运营商不在同一类别,但我不完全理解如何。所以我或多或少地随意尝试了一些事情,例如用::
等取代::
,但没有成功。
我错过了什么,有办法做我想做的事吗?
答案 0 :(得分:8)
According to MSDN,冒号实际上不能在运营商名称中使用。这似乎与FSharp.org的the F# specification相矛盾,我不确定那里发生了什么。但我们可以在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>
is defined,您会发现(::)
实际上不是运算符,而是案例构造函数:
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)
现在,奇怪的是,如果我尝试使用另一个看起来像运算符的名称作为案例构造函数,我会收到此错误:
> type A = | ( |> ) of string * int
Script.fsx(1,14): error FS0053: Discriminated union cases and exception labels must be uppercase identifiers
这意味着(::)
在某种程度上特殊(顺便说一下,([])
也是如此。
所以底线似乎是 - 不,你不能这样做
但为什么你甚至需要?也许你可以选择一个更可接受的运算符名称,它仍然可以表达&#34; const&#34;的语义。 - 比方说,(<+>)
?