2012-03-16 21 views
5

的代碼少部分的突出問題:柯里在F#「靈活的類型」

open System.IO 

let do_smth i (stm : #System.IO.Stream) = // val do_smth : 'a -> #Stream -> unit 
    (*....*) 
    () 

type SomeOps = SomeOps with 
    static member op (i : int) = do_smth i 

let test_currying i = do_smth i   // val test_currying : 'a -> (Stream -> unit) 
              // NB: Stream, not #Stream 
let main() = 
    use stm = new System.IO.MemoryStream() 
    test_currying 42 stm // OK, upcasted to Stream somehow 
    SomeOps.op 42 stm  // compiler error! 

有人能解釋一下,爲什麼是編譯器的行爲在最後兩行如此不同?爲什麼我們在test_currying函數中丟失了信息(關於靈活#Stream)?

回答

3

這看起來像是一個bug。編譯器處理使用let構造的不同函數和編寫爲static member的函數。

特別是,我認爲它不會爲未在成員聲明中顯式聲明的成員參數插入靈活類型(即參數可能是部分函數應用的結果,也可能是使用fun構造創建的) 。

演示該行爲不使用靈活型,看起來像最簡單的例子:

type A = 
    static member op = fun (s:obj) ->() 
module B = 
    let op = fun (s:obj) ->() 

A.op "A" // Error 
B.op "A" // Ok 

根據規範(?第14.4.2,由Brian在刪除()答案公佈),靈活不管調用的函數是成員還是let-bound值,都應該插入允許使用超類型的類型。

+0

所以,這是正確的行爲,對吧? – qehgt 2012-03-19 19:05:48

+0

我不認爲編譯器目前所做的是正確的行爲。我沒有看到兩個案件行爲不同的理由。這就是爲什麼我說它看起來像一個bug。 – 2012-03-20 01:08:05

+0

好的,我明白了。謝謝。 – qehgt 2012-03-20 03:40:37