Estoy tratando de llamar a un método .NET aceptando un genérico IEnumerable<T>
desde F # usando un seq<U>
tal que U es una subclase de T. Esto no funciona de la manera que lo esperaba haría:F # y covarianza de interfaz: ¿qué hacer? (específicamente seq <> aka IEnumerable <>)
con la impresora siguiente sencillo:
let printEm (os: seq<obj>) =
for o in os do
o.ToString() |> printfn "%s"
Estos son los resultados que obtengo:
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 '[email protected][System.Int32]'
// to type 'System.Collections.Generic.IEnumerable`1[System.Object]'.
Idealmente, me gusta la primera sintaxis para trabajar - o algo tan cerca como po posible, con comprobación del tipo de tiempo de compilación. No entiendo dónde encuentra el compilador una función seq<string> -> unit
en esa línea, pero aparentemente la covarianza de IEnumerable no funciona y eso de alguna manera da como resultado ese mensaje de error. El uso de una conversión explícita da como resultado un mensaje de error razonable, pero tampoco funciona. Usar un casting en tiempo de ejecución funciona, pero solo para cadenas, las entradas fallan con una excepción (desagradable).
Estoy tratando de interoperar con otro código .NET; es por eso que necesito tipos específicos de IEnumerable.
¿Cuál es la forma más limpia y preferiblemente eficiente de transmitir interfaces co o contravariantes como IEnumerable en F #?
Como dice desco, la solución más limpia es alterar (o eliminar) la declaración de tipo de 'os' (si es posible). En una nota no relacionada, 'o.ToString |> printfn"% s "' se puede escribir de forma más concisa como 'o |> printfn "% O" '. – kvb
@kvb Creo que @Eamon no tiene problemas con la función 'printfn'. –