为自定义集合定义cons(::)运算符 [英] Define the cons (::) operator for custom collections

查看:85
本文介绍了为自定义集合定义cons(::)运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用相当受欢迎的 FSharpx.Collections 包,尤其是 NonEmptyList 类型.

I am using the fairly popular FSharpx.Collections package, and in particular the NonEmptyList type.

此类型提供NonEmptyList.cons功能,但我想像常规List(即head :: tail)一样使用::运算符.由于tail必须已经是NonEmptyList<'a>,所以与List::运算符应该没有任何冲突.

This type provides the NonEmptyList.cons function, but I want to use the :: operator as with regular List, i.e. head :: tail. Since tail must already be a NonEmptyList<'a>, there shouldn't be any conflict with List's ::operator.

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

However, it seems I cannot define the operator. This:

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

导致编译错误:

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

我知道::与其他运算符不在同一个类别中,但是我不完全了解操作方式.因此,我或多或少地尝试了一些尝试,例如用op_cons替换::之类的方法,但没有成功.

I know that :: is not quite in the same category as other operators, but I don't fully understand how. So I tried a few things more or less at random, such as replacing :: with op_cons and the like, without success.

我错过了什么吗,有什么方法可以做我想做的事吗?

Am I missing something, and is there a way to do what I want to do?

推荐答案

根据到MSDN ,实际上不能在运算符名称中使用冒号.这似乎与FSharp的 F#规范相矛盾. org,我不确定那里发生了什么.但是我们可以在FSI中进行验证:

According to MSDN, colon cannot actually be used in operator name. This seems to contradict the F# specification from FSharp.org, I'm not sure what's going on there. But we can verify that in 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

如果您查看 List<'T>的定义方式,您会发现(::)实际上不是运算符,而是 case构造函数:

If you look at how List<'T> is defined, you'll find that (::) is not actually an operator, but a case constructor:

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

当然,您可以定义自己的DU类型,并将其作为构造函数名称:

And sure enough, you can define your own DU type with that as constructor name:

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

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

现在,奇怪的是,如果我尝试使用另一个看起来像操作符的名称作为大小写构造函数,则会出现此错误:

Now, oddly, if I try to use another operator-ish-looking name as case constructor, I get this error:

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

这意味着(::)在某种程度上是特殊的(顺便说一句,([])也是).

Which means that (::) is somehow special (and so is ([]), by the way).

所以底线似乎是-不,你不能那样做.
但是,为什么您甚至需要?也许您可以选择一个更可接受的运算符名称,该名称仍会表示"cons"的语义-例如(<+>)?

So the bottom line seems to be - no, you can't do that.
But why do you even need to? Can you, perhaps, settle for a more acceptable operator name, which would still express the semantics of "cons" - like, say, (<+>)?

这篇关于为自定义集合定义cons(::)运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆