2010-12-19 13 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#コンパイラは実際にunitをILに含むコードを生成しないという問題があります。それはvoid(戻り値の型として使用される場合)または空の引数リスト(メソッドまたは関数の引数として使用される場合)で置き換えられます。

これはMyClass型では、コンパイラはstringを取り、voidを返すメソッドとしてMyFunメンバーをコンパイルすることを決定したことを意味し(ただし、ジェネリック型引数としてvoidを使用することはできませんので、これだけでは動作しません)。原則として、コンパイラはこの場合実際のunit型を使用することができます(それが有効な唯一の方法なので)が、他の場所では他の不一致が生じる可能性があります。

作成すると、MyUnitというトリックは、問題を解決するための完璧な方法です。コアのF#ライブラリでさえ、unitのいくつかの制限(およびコンパイル方法)に対処するために、実装のいくつかの場所(非同期ワークフロー内)でMyUnitのようなものを使用します。

+0

ありがとう。 –

+0

@Stefan: 'unit'型を(関数または型に対して)引数として使用すると、一般的に問題ありません。このバグ/制限は抽象メンバを実装するときにのみ現れるでしょう(これは、F#コンパイラにとって少し面倒な領域です)。 –

+1

興味深いことに、C#で動作し、F#で関数を使用できます。おそらくバグとして報告されるべきです。 –

関連する問題