超载+ F# 中的运算符

发布于 2024-12-09 01:53:01 字数 661 浏览 2 评论 0原文

所以我有这个:

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 '+'

网络上的文档和示例很脆弱,尽管我用谷歌搜索,但我一直无法让它工作。基本上,来自 python 背景,我希望我的列表操作语法像我习惯的那样简洁:它不应该需要超过 1 个中缀表示法的字符。

So i have this:

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)

and I want to convert the last line into

for x in a + b do
    Console.WriteLine(x)

but doing so gives me a

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

The documentation and examples on the web are flakey, and despite my google-fu i have been unable to get it to work. Basically, coming from a python background, I want to get my list manipulation syntax as terse as I am used to: it should not need more than 1 character in infix notation.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

○闲身 2024-12-16 01:53:01

首先,重写运算符应该以元组形式声明,而不是以进位形式声明。在您的情况下:

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

其次,修复该问题后,编译器会引发“扩展成员无法提供运算符重载。请考虑将运算符定义为类型定义的一部分。” 警告。 F# 中的重载运算符:(/) 中已详细讨论了一些解决方法。

First, overriding operators should be declared in the tuple form, not in the carried form. In your case:

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

Second, after you fix that, the compiler raises the "Extension members cannot provide operator overloads. Consider defining the operator as part of the type definition instead." warning. There are some workarounds which have been discussed thoroughly in Overload operator in F#: (/).

猫卆 2024-12-16 01:53:01

请注意,@ 已经是用于连接列表的 1 字符中缀运算符。

Note that @ is already a 1-char infix operator to concat lists.

孤单情人 2024-12-16 01:53:01

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

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)

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

Actually there is a way to 're-wire' existing operators, using static constraints and overloads.

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

By using the ternary operator the static constraints will be automatically inferred, another option would be to create a method and write the constraints by hand.
The first overload cover the case you want to add (lists), the second covers the existing definition.

So now in your code you can do:

for x in (+) a b do
    Console.WriteLine(x)

And that will not break existing (+) for numeric types.

煮茶煮酒煮时光 2024-12-16 01:53:01

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

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

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)

As pointed out by the other answers, you cannot add implementation of + to an existing type, because extension members are ignored and standalone let binding hides the default (overloaded) implementation.

If you wanted to use + (which is not really needed because F# library contains operator @), you would have to write wrapper for F# list that supports the operator directly:

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)
思念绕指尖 2024-12-16 01:53:01

我认为使用扩展方法的运算符重载不起作用。您可以做的是使用以下命令为列表 (+) 定义全局运算符重载:

let inline (+) (f : List<'a>) (s : List<'a>) = f.Concat(s) 

I think operator overloading using extension method doesn't work. What you can do is define a global operator overload for list (+) using:

let inline (+) (f : List<'a>) (s : List<'a>) = f.Concat(s) 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文