2011-11-17 82 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"])) 

打印「失敗」兩次,我想它應該,因爲我給我一個功能obj -> list<String>,這不是obj -> list<obj>。有什麼方法可以讓它們匹配嗎?在匿名函數出來之前,我可以將每個列表上傳到list<obj>,或者在把它放入列表之前,我可以將所有內容上傳到objF#模式匹配:匹配函數/子類型列表?

這些作品中的任何一個都可以匹配,但我認爲這是協變/逆變意味着已經解決的問題?糾正我,如果我錯了

+2

F#不支持co/contravariance。 – Daniel

回答

7

不幸的是,你不能解決這個使用任何內置的模式匹配。

要找出obj值是否爲F#函數的唯一方法是使用F#Reflection並調用該類型的FSharpType.IsFunction方法。您可以檢查像這樣在你的榜樣的情況:

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 

你可以封裝的行爲在F#活躍模式,使語法更好一點(和使用模式的類型匹配)。但是,另一個問題是,這不會給你一個你可以用來動態調用函數的函數。我不認爲這是一個內置的庫函數,因此您可能需要使用.NET反射來動態調用Invoke方法。

編輯:在SO上也有類似的相關問題。普遍的問題是,你對一個特定的泛型類型的一些(任何)實例化匹配,所以同樣的問題與列表等見例如出現了: