2017-02-17 13 views
3

Предположим, у меня есть следующий код:Коллекция объектов, которые реализуют общий интерфейс в F #

type A = 
    abstract member hi: string 

type B() = 
    interface A with 
    member self.hi: string = "Hello" 

type C() = 
    interface A with 
    member self.hi: string = "Yo" 

я могу сделать F # s тип проверки счастливый список объектов типа A и B до тех пор, как я явно указать тип интерфейса, ala:

let l: A list = [ B(); C() ] 

Но я немного в тупике, когда общие параметры вводят изображение. Например,

type A<'T> = 
    abstract member thing: 'T 

type B() = 
    interface A<int> with 
    member self.thing: int = 1 

type C() = 
    interface A<string> with 
    member self.thing: string = "Yo" 

и я пытаюсь использовать что-то вроде

let l: A<_> list = [B(); C()] 

F #, кажется, хочет упорно заполнить параметр универсального типа:

error FS0001: The type 'C' is not compatible with the type 'A<int>' 

Следует заметить, что я использовал этот шаблон в Java со стандартными интерфейсами и в Scala с чертами, поэтому я удивлен, что я не могу сделать это в F #. Что мне здесь не хватает?

ответ

4

Использование _ в позиции параметров типа в основном говорит компилятору «вывести тип для меня». Первый полностью определенный тип в списке - A<int>, поэтому _ зафиксирован на int. Вам необходимо предоставить (наименее распространенный) супертип всех элементов списка самостоятельно. Как F # не поддерживает интерфейс ковариации в дженериков, все, что вы можете сделать здесь obj: let l: obj list = [B(); C()]

Обратите внимание, что это верно для C#, а также, как и дисперсия приходит в игру только для ссылочных типов:

interface IInvariant<T> 
{ 
    T Item { get; } 
} 

interface ICovariant<out T> 
{ 
    T Item { get; } 
} 

class Foo : IInvariant<int>, ICovariant<int> 
{ 
    public int Item { get; } 
} 

class Bar : IInvariant<string>, ICovariant<string> 
{ 
    public string Item { get; } 
} 

class Baz 
{ 
    static void Check() 
    { 
     var a = new IInvariant<object>[] { new Foo(), new Bar() }; 
     // CS0266 Cannot implicitly convert type 'Foo' to 'C.IInvariant<object>' 
     // CS0266 Cannot implicitly convert type 'Bar' to 'C.IInvariant<object>' 

     var b = new ICovariant<object>[] { new Foo(), new Bar() }; 
     // CS0266 Cannot implicitly convert type 'Foo' to 'C.ICovariant<object>' 
    } 
} 

в F # вы можете создать дискриминационный союз для сбора информации о типе:

type InvariantWrapper = 
| Integer of IInvariant<int> 
| Stringy of IInvariant<string> 

let c = [ Integer(Foo()); Stringy(Bar()) ] 
4

F # напрямую не поддерживает гетерогенное использование параметров типа, как, что: _ означает определенный конкретный неопределенный тип, а не любое количество неуказанных типов. Если вы отчаянно хотите сделать что-то подобное, в системе типа .NET существует механическое, но неудобное кодирование экзистенциальных типов, но я бы рекомендовал против него, если не будет особо особого преимущества.

Также обратите внимание, что даже если бы вы могли делать то, что хотели, вы не могли бы многое сделать с этим списком - какую операцию вы могли бы выполнить на любом его элементе?

 Смежные вопросы

  • Нет связанных вопросов^_^