2014-01-13 71 views
1

我寫了我認爲非常直接的F#代碼,但編譯器似乎正在跳出類型推斷。而不是從受歧視的工會中推斷出來,而是通過一個通用的推論。但我不明白爲什麼,因爲我的代碼不允許通用推理。爲什麼F#「Generic-izing」我的歧視聯盟

下面的代碼:

module Log 

open System 

type LogInput = 
    | Message of (int * string) 
    | Error of Exception 
    | Process of (string * unit -> int) 

let log i = 
    match i with 
    | Message(indent, str) -> 
     str 
     |> printfn "Message() %s%s" (String.replicate (indent * 4) " ") 
    | Error(err) -> 
     err.ToString() 
     |> printfn "Error() %s" 
    | Process(name, f) -> 
     printfn "Beginning %s..." name 
     printfn "Completed %s\nReturn Code: %i" name <| f() 

編譯器正確推斷爲indentstrerr類型,但要推斷'a'bnamef(不使得或者基於感歧視的聯盟或使用)。這是怎麼回事?

錯誤消息:

Log.fs(18,16): error FS0001: This expression was expected to have type 
    string * unit -> int  
but here has type 
    'a * 'b  

回答

3

糟糕!想通了。

我錯誤地定義了類型。我的意思是接受一個字符串和一個函數接受單元並返回int。相反,我定義了一個採用字符串和單位並返回int的函數。以下是我如何更正了我的歧視聯盟中的定義:

type LogInput = 
    | Message of (int * string) 
    | Error of Exception 
    | Process of (string * (unit -> int)) 

混淆運算符優先級的經典案例。在這裏看到更多:

Symbol and Operator Reference (F#)

*->一個優先級數字,所以stringunit元組戰勝了功能unit -> int

+1

運算符優先級的定義是這樣的方式,因爲它是編寫一個帶元組的函數(比如,.NET方法是這樣定義的)比一個元素是函數的元組(這裏是你想要的)更常見。 – Tarmil

+1

@Tarmil - 同意,這是更常見的用例,它是有道理的。但是,對於這個語言來說,這是一個相當新的東西,一旦我把它放在我的腦海裏,'string * unit - > int'意味着'string *(unit - > int)',我無法弄清楚發生了什麼。如果編譯器輸出更加明確(比如'(string * unit) - > int'),我會立即識別錯誤。 – JDB