所以我有这个:
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)
我希望将最后一行转换为
for x in a + b do
Console.WriteLine(x)
但这样做会给我一个
The type 'int list' does not support any operands named '+'
网络上的文档和示例很有趣,尽管我的google-fu我还是无法让它工作。基本上,来自python背景,我想让我的列表操作语法像我习惯的那样简洁:它不应该在中缀表示法中需要超过1个字符。
答案 0 :(得分:8)
请注意,@
已经是一个1-char中缀运算符,用于连接列表。
答案 1 :(得分:7)
实际上,有一种方法可以使用静态约束和重载来“重新连接”现有的运算符。
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)
这不会破坏数字类型的现有(+)
。
答案 2 :(得分:5)
首先,覆盖运算符应该以元组形式声明,而不是以携带形式声明。在你的情况下:
type Microsoft.FSharp.Collections.List<'a> with
static member (+) (first: List<'a>, second: List<'a>) =
first.Concat(second)
其次,在您修复之后,编译器会引发"Extension members cannot provide operator overloads. Consider defining the operator as part of the type definition instead."
警告。有一些解决方法已经在Overload operator in F#: (/)中进行了详尽的讨论。
答案 3 :(得分:3)
正如其他答案所指出的,您无法将+
的实现添加到现有类型,因为会忽略扩展成员并且独立let
绑定会隐藏默认(重载)实现。
如果你想使用+
(因为F#库包含operator @
而不是真的需要),你必须编写直接支持运算符的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)
答案 4 :(得分:0)
我认为使用扩展方法的运算符重载不起作用。你可以做的是使用:
为列表(+)定义一个全局运算符重载let inline (+) (f : List<'a>) (s : List<'a>) = f.Concat(s)