F# 超载+;F中的运算符#

F# 超载+;F中的运算符#,f#,operator-overloading,F#,Operator Overloading,所以我有这个: open System open System.Linq open Microsoft.FSharp.Collections type Microsoft.FSharp.Collections.List<'a> with static member (+) (First : List<'a>) (Second : List<'a>) = First.Concat(Second) let a = [1; 2; 3; 4;

所以我有这个:

open System
open System.Linq
open Microsoft.FSharp.Collections
type Microsoft.FSharp.Collections.List<'a> with
    static member (+) (First : List<'a>) (Second : List<'a>) =
        First.Concat(Second)

let a = [1; 2; 3; 4; 54; 9]
let b = [3; 5; 6; 4; 54]


for x in List.(+) a b do
    Console.WriteLine(x)
但这样做给了我一个机会

The type 'int list' does not support any operands named '+'

网络上的文档和示例都是不完整的,尽管我使用了google fu,但我还是无法让它正常工作。基本上,我来自python的背景,我想让我的列表操作语法像我习惯的那样简洁:它不需要超过1个字符的中缀符号

首先,重写运算符应该以元组形式声明,而不是以携带形式声明。就你而言:

type Microsoft.FSharp.Collections.List<'a> with
    static member (+) (first: List<'a>, second: List<'a>) =
        first.Concat(second)

键入Microsoft.FSharp.Collections.List,第二个:List我认为使用扩展方法重载运算符不起作用。您可以使用以下命令定义列表(+)的全局运算符重载:

let inline(+)(f:List)=f.Concat(s)

请注意,
@
已经是concat列表的1字符中缀运算符。

正如其他答案所指出的,您不能将
+
的实现添加到现有类型,因为扩展成员被忽略,而独立的
绑定隐藏默认(重载)实现

如果您想使用
+
(实际上并不需要,因为F#library包含运算符
@
),则必须为直接支持运算符的F#list编写包装器:

open System.Collections
open System.Collections.Generic

/// Wrapper for F# list that exposes '+' operator and 
/// implements 'IEnumerable<_>' in order to work with 'for'
type PlusList<'T>(list : list<'T>) =
  member x.List = list
  static member (+) (first : PlusList<'a>, second : PlusList<'a>) =
    first.List @ second.List
  interface IEnumerable with
    member x.GetEnumerator() = (list :> IEnumerable).GetEnumerator()
  interface IEnumerable<'T> with
    member x.GetEnumerator() = (list :> IEnumerable<_>).GetEnumerator()

// Simple function to wrap list
let pl l = PlusList<_>(l)

let a = pl [1; 2; 3; 4; 54; 9]
let b = pl [3; 5; 6; 4; 54]

for x in a + b do
  System.Console.WriteLine(x)
opensystem.Collections
open System.Collections.Generic
///公开“+”运算符和
///实现“IEnumerable”以便使用“for”
类型(PlusList)=
成员x.列表=列表
静态成员(+)(第一个:PlusList)=
first.List@second.List
接口IEnumerable with
成员x.GetEnumerator()=(列表:>IEnumerable).GetEnumerator()

接口IEnumerable实际上,有一种方法可以使用静态约束和重载“重新连接”现有运算符

type ListExtension = ListExtension with
    static member        (?<-) (ListExtension, a , b) = a @ b
    static member inline (?<-) (ListExtension, a , b) = a + b

let inline (+) a b = (?<-) ListExtension a b

// test

let lst = [1;2] + [3;4]
// val lst : int list = [1; 2; 3; 4]

let sum = 1 + 2 + 3 + 4
// val sum : int = 10

这不会破坏现有的数值类型的
(+)

它可以工作,但它会覆盖任何类型的所有(+)运算符。所以你不能再调用2+3来表示整数了。这与运算符重载的想法背道而驰。。你是对的。。。奇怪的是,F#编译器没有使用用于确定要使用的正确运算符的值的类型。这是否意味着F#不允许您用多个签名重载一个方法,然后在每个使用点(a.l.a.Java)选择正确的一个?此限制仅适用于let绑定函数。你仍然可以用通常的方式重载成员函数。哦,我不知道。谢谢@但是有一种方法可以绕过这个限制,看看我的答案。
open System.Collections
open System.Collections.Generic

/// Wrapper for F# list that exposes '+' operator and 
/// implements 'IEnumerable<_>' in order to work with 'for'
type PlusList<'T>(list : list<'T>) =
  member x.List = list
  static member (+) (first : PlusList<'a>, second : PlusList<'a>) =
    first.List @ second.List
  interface IEnumerable with
    member x.GetEnumerator() = (list :> IEnumerable).GetEnumerator()
  interface IEnumerable<'T> with
    member x.GetEnumerator() = (list :> IEnumerable<_>).GetEnumerator()

// Simple function to wrap list
let pl l = PlusList<_>(l)

let a = pl [1; 2; 3; 4; 54; 9]
let b = pl [3; 5; 6; 4; 54]

for x in a + b do
  System.Console.WriteLine(x)
type ListExtension = ListExtension with
    static member        (?<-) (ListExtension, a , b) = a @ b
    static member inline (?<-) (ListExtension, a , b) = a + b

let inline (+) a b = (?<-) ListExtension a b

// test

let lst = [1;2] + [3;4]
// val lst : int list = [1; 2; 3; 4]

let sum = 1 + 2 + 3 + 4
// val sum : int = 10
for x in (+) a b do
    Console.WriteLine(x)