F#中的重载+运算符

Li *_*oyi 5 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; 54; 9]
let b = [3; 5; 6; 4; 54]


for x in List.(+) a b do
    Console.WriteLine(x)
Run Code Online (Sandbox Code Playgroud)

我想把最后一行转换成

for x in a + b do
    Console.WriteLine(x)
Run Code Online (Sandbox Code Playgroud)

但这样做给了我一个

The type 'int list' does not support any operands named '+'
Run Code Online (Sandbox Code Playgroud)

网络上的文档和示例都很有趣,尽管我的google-fu仍然无法让它发挥作用.基本上,从蟒蛇背景的,我想我的列表操作语法简洁,因为我用的:它不应该需要在中间符号超过1个字符.

Bri*_*ian 8

请注意,@已经是一个1-char中缀运算符来连接列表.


Gus*_*Gus 8

实际上,有一种方法可以使用静态约束和重载来"重新连接"现有的运算符.

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
Run Code Online (Sandbox Code Playgroud)

通过使用三元运算符,将自动推断静态约束,另一种选择是创建方法并手动编写约束.第一个重载覆盖了要添加的情况(列表),第二个覆盖了现有的定义.

所以现在在你的代码中你可以做到:

for x in (+) a b do
    Console.WriteLine(x)
Run Code Online (Sandbox Code Playgroud)

这不会破坏(+)数字类型的存在.


pad*_*pad 5

首先,应以元组形式而不是带值形式声明覆盖运算符。在您的情况下:

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

其次,在解决此问题之后,编译器将"Extension members cannot provide operator overloads. Consider defining the operator as part of the type definition instead."发出警告。在F#中的Overload运算符中有一些变通办法已被彻底讨论:(/)