2011-11-17 8 views
5
let f (O: obj) = 
    match O with 
     | :? (obj -> list<obj>) -> "win" 
     | :? list<obj> -> "list!" 
     | _ -> "fail" 

Console.WriteLine(f(fun x -> ["lol"])) 
Console.WriteLine(f(["lol"])) 

imprime "falla" dos veces, como supongo que debería, porque le estoy dando una función obj -> list<String>, que no es un obj -> list<obj>. ¿Hay alguna forma de hacerlos coincidir? Pude subir cada lista a list<obj> antes de hacer una función anónima, o pude subir todo al obj antes de ponerlo en la lista.F # coincidencia de patrones: funciones coincidentes/listas de subtipos?

Cualquiera de esos trabajos hace que coincida, pero pensé que este era el problema que la covarianza/contravarianza debía haber resuelto ya? Corrígeme si me equivoco

+2

F # no admite co/contravariancia. – Daniel

Respuesta

7

Lamentablemente, no puede resolver esto usando cualquier coincidencia de patrón incorporada.

La única manera de averiguar si un valor obj es alguna función F # es utilizar F # Reflection y llamar al método FSharpType.IsFunction en el tipo. Puede comprobar si el caso en su ejemplo como este:

open System  
open Microsoft.FSharp.Reflection  

let f (o : obj) = 
    let ty = o.GetType() 
    if FSharpType.IsFunction(ty) then 
    let tyFrom, tyTo = FSharpType.GetFunctionElements(ty) 
    if tyTo.IsGenericType && tyTo.GetGenericTypeDefinition() = typedefof<list<_>> then 
     printfn "win" 
    else 
     printfn "wrong function" 
    else 
    printfn "not a function" 

Console.WriteLine(f(fun x -> "lol")) // wrong function 
Console.WriteLine(f(fun x -> ["lol"])) // win 
Console.WriteLine(f(["lol"]))   // not a function 

Usted puede encapsular el comportamiento en un patrón # activa F para realizar la sintaxis un poco más agradable (y el uso de patrones sobre los tipos). Sin embargo, otro problema es que esto no le da una función que podría usar para invocar la función dinámicamente. No creo que haya una función de biblioteca incorporada para esto, por lo que probablemente necesite usar la reflexión .NET para llamar al método Invoke de forma dinámica.

EDIT: Ha habido preguntas relacionadas similares en SO. El problema general es que estás a juego en contra de algunos (cualquiera) de instancias de un tipo genérico específico, por lo que el mismo problema se plantea con las listas etc. Véase, por ejemplo:

Cuestiones relacionadas