F # и ковариация интерфейса: что делать? (в частности, seq <> aka IEnumerable <>)

я пытаюсь вызвать .NET-метод, принимающий общий IEnumerable из F #, используя seq таким образом, что U является подклассом T. Это не работает так, как я ожидал:

Со следующим простым принтером:

let printEm (os: seq<obj>) = 
    for o in os do
        o.ToString() |> printfn "%s"

Вот результаты, которые я получаю:

Seq.singleton "Hello World"  |> printEm // error FS0001; 
//Expected seq<string> -> 'a but given seq<string> -> unit

Seq.singleton "Hello World"  :> seq<obj> |> printEm // error FS0193;
//seq<string> incompatible with seq<obj>

Seq.singleton "Hello World"  :?> seq<obj> |> printEm // works!

Seq.singleton 42 :> seq<obj> |> printEm // error FS0193
Seq.singleton 42 :?> seq<obj> |> printEm // runtime InvalidCastException!
//Unable to cast object of type 'mkSeq@541[System.Int32]'
// to type 'System.Collections.Generic.IEnumerable`1[System.Object]'.

В идеале, я бы хотел, чтобы первый синтаксис работал - или что-то как можно ближе к нему, с проверкой типов во время компиляции. Я не понимаю, где компилятор находит функцию seq -> unit в этой строке, но, по-видимому, ковариация для IEnumerable не работает, и это каким-то образом приводит к тому сообщению об ошибке. Использование явного приведения приводит к разумному сообщению об ошибке, но это тоже не работает. Использование приведений во время выполнения работает, но только для строк, целые числа не работают с исключением (неприятно).

Я пытаюсь взаимодействовать с другим кодом .NET; вот почему мне нужны определенные типы IEnumerable.

What ' s самый чистый и предпочтительно эффективный способ приведения ко- или контравариантных интерфейсов, таких как IEnumerable в F #?

12
задан Eamon Nerbonne 17 November 2010 в 10:43
поделиться