2010-12-19 44 views
16

有誰知道爲什麼這不能編譯?由於單元導致F#接口繼承失敗

type MyInterface<'input, 'output> = 
    abstract member MyFun: 'input -> 'output 

type MyClass() = 
    interface MyInterface<string, unit> with 
     member this.MyFun(input: string) =() 
    //fails with error FS0017: The member 'MyFun : string -> unit' does not have the correct type to override the corresponding abstract method. 
type MyUnit = MyUnit 
type MyClass2() = 
    //success 
    interface MyInterface<string, MyUnit> with 
     member this.MyFun(input: string) = MyUnit 

回答

15

這看起來像在F#語言討厭極端情況,但我不知道這是否有資格作爲由設計限制,或在編譯器中的錯誤。如果是通過設計限制,那麼錯誤消息應該說(因爲目前沒有多大意義)。

無論如何,問題在於F#編譯器不會生成IL中實際包含unit類型的代碼。它用void(用作返回類型)或空參數列表(用作方法或函數參數)替換它。

這意味着,在MyClass類型,編譯器決定編譯MyFun成員爲需要string並返回void的方法(但你不能使用void爲泛型類型參數,所以這是行不通的)。原則上,編譯器可以在這種情況下使用實際的unit類型(因爲這是實現它的唯一方法),但這可能會在其他地方產生其他不一致。

我認爲,創建MyUnit的訣竅是解決問題的完美方法。即使是核心F#庫在實現的某些地方(在異步工作流程中)也會使用類似MyUnit的東西來處理unit(及其編譯方式)的某些限制。

+0

感謝Tomas。我還沒有在其他地方看到過這個問題(例如,在let的正常函數中) – 2010-12-19 23:43:07

+0

@Stefan:如果使用'unit'類型作爲參數(函數或類型),那麼它通常很好。這個bug /限制可能只在實現抽象成員時纔會出現(這對F#編譯器來說有點棘手,因爲在.NET中繼承的複雜性非常複雜) – 2010-12-20 00:08:02

+1

有趣的是,它可以在C#中工作,並且我可以使用F#中的函數。可能應該報告爲一個錯誤。 – 2011-01-12 05:55:38