Перегрузка + оператор в F # - PullRequest
5 голосов
/ 08 октября 2011

Итак, у меня есть это:

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 символа в инфиксной нотации.

Ответы [ 5 ]

8 голосов
/ 08 октября 2011

Обратите внимание, что @ уже является 1-символьным инфиксным оператором для объединения списков.

7 голосов
/ 04 декабря 2011

На самом деле существует способ «переназначить» существующие операторы, используя статические ограничения и перегрузки.

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)

И это не сломаетсясуществующий (+) для числовых типов.

5 голосов
/ 08 октября 2011

Во-первых, переопределяющие операторы должны быть объявлены в форме кортежа, а не в переносимой форме.В вашем случае:

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.".Есть некоторые обходные пути, которые подробно обсуждались в операторе перегрузки в F #: (/).

3 голосов
/ 08 октября 2011

Как указано в других ответах, вы не можете добавить реализацию + к существующему типу, поскольку члены расширения игнорируются, а автономное связывание 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)
0 голосов
/ 08 октября 2011

Я думаю, перегрузка операторов с использованием метода расширения не работает.Что вы можете сделать, это определить глобальную перегрузку оператора для списка (+), используя:

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