2010-10-04 3 views
2

У меня есть тип, реализующий IEnumerable<T> интерфейс, все в порядке:Является ли это ошибкой F #?

open System 

type Bar() = 

    interface Collections.IEnumerable with 
     member x.GetEnumerator() = null 

    interface Collections.Generic.IEnumerable<int> with 
     member x.GetEnumerator() = null 

Но все идет не так, если тип наследует IEnumerable реализацию интерфейса с помощью базового типа:

open System 

type Foo() = 
    interface Collections.IEnumerable with 
     member x.GetEnumerator() = null 

type Bar() = 
    inherit Foo() 

    interface Collections.Generic.IEnumerable<int> with 
     member x.GetEnumerator() = null 

Код выше продуцирует тип ошибки вывода:

  • The member 'GetEnumerator<'a0 when 'a0 : null> : unit -> 'a0 when 'a0 : null' does not have the correct type to override any given virtual method

  • The member 'GetEnumerator<'a0 when 'a0 : null> : unit -> 'a0 when 'a0 : null' does not have the correct number of method type parameters. The required signature is 'GetEnumerator : unit -> Collections.Generic.IEnumerator<int>'.

я делаю что-то неправильно, или это F # ошибка компилятора?

Microsoft (R) F# 2.0 Interactive build 4.0.30319.1


Update более канонический пример:

type IFoo  = abstract Bar : obj list 
type IFoo<'a> = abstract Bar : 'a list 
       inherit IFoo 
/* ok */ 
type Foo  = interface IFoo  with member x.Bar = [] 
        interface IFoo<Foo> with member x.Bar = [] 
/* fail */ 
type FooBase = interface IFoo  with member x.Bar = [] 
type FooDerived = interface IFoo<Foo> with member x.Bar = [] // <--- 
        inherit FooBase 
/* 
error FS0017: The member 'get_Bar : unit -> 'a list' does not 
    have the correct type to override any given virtual method. 
*/ 
+0

Можете ли вы выслать свой фактический код? – Gabe

ответ

2

Это не ошибка, это просто определение типа терпит неудачу из F # может реализовать унаследованный интерфейс в производной декларации реализации интерфейса:

type IA = abstract A : int 
type IB = inherit IA 
type IC = inherit IB 

type Baz = 
    interface IC with 
     member x.A = 1 

Так в моем примере я должен указать правильный тип возвращаемого значения явно, потому что member x.GetEnumerator() в производном Bar тип может соответствовать как IEnumerable.GetEnumerator(), так и IEnumerable<T>.GetEnumerator().

+1

Просто понял, что тоже;) Да, проблема в том, что тип GetEnumerable неоднозначен, если явно не указано, поскольку IEnumerable и IEnumerable <'a> специфицируют такой метод. – Frank

5

Компилятор не может вывести правильный тип из вашего "нулевого" -внедрения. Попытка

open System 

type Foo() = 
    interface Collections.IEnumerable with 
     member x.GetEnumerator() = null 

type Bar() = 
    inherit Foo() 

    interface Collections.Generic.IEnumerable<int> with 
     member x.GetEnumerator() : Collections.Generic.IEnumerator<int> = null 

ОБНОВЛЕНИЕ:
Причина заключается в том, что тип GetEnumerator метода, реализованного Bar типа Неоднозначный, как IEnumerable<'a> орудий/наследуют неуниверсальные IEnumerable который также определяет (не родовой) GetEnumerator способ. Итак, как должен компилятор заключить, какой метод вы пытаетесь реализовать, если все, что он получает, равен нулю? Поэтому в этом случае нам нужна аннотация типа.

+0

ok, давайте возьмем такой интерфейс: 'type Foo <'a> = abstract M: unit -> 'a' и попытайтесь реализовать его без указания каких-либо типов, кроме обязательных для объявления:' type Bar() = interface Foo с элементом xM() = null' - он работает отлично! – ControlFlow

+0

Конечно, но это не то же самое. Эквивалентный образец скорее прочитает 'type Boo <'a> = abstract M: 'a' и' type Foo <'a> = abstract M: unit -> Boo <'a> 'и, наконец,' type Bar() = interface Foo с элементом xM() = null '. Опять же, компилятор не может вывести Boo <_> (например, IEnumerator <_>). – Frank

+0

Хм, ты прав, но как насчет первого примера? Как там выведен правильный тип? – ControlFlow