この関数:
let convert (v: float<_>) =
match v with
| :? float<m> -> v / 0.1<m>
| :? float<m/s> -> v / 0.2<m/s>
| _ -> failwith "unknown"
エラーが発生します
タイプ'float<'u>'には適切なサブタイプがなく、タイプテストまたは実行時強制のソースとして使用することはできません。
一致する測定単位をパターン化する方法はありますか?
この関数:
let convert (v: float<_>) =
match v with
| :? float<m> -> v / 0.1<m>
| :? float<m/s> -> v / 0.2<m/s>
| _ -> failwith "unknown"
エラーが発生します
タイプ'float<'u>'には適切なサブタイプがなく、タイプテストまたは実行時強制のソースとして使用することはできません。
一致する測定単位をパターン化する方法はありますか?
@kvbが詳細に説明しているように、問題は、測定単位がタイプの一部であるということです。これは、とfloat<m>
は異なるタイプであることを意味しますfloat<m/s>
(残念ながら、この情報は実行時に値の一部として保存されません)。
つまり、実際には、2つの異なるタイプの入力で機能する関数を作成しようとしています。クリーンな機能ソリューションは、最初のタイプまたは2番目のタイプのいずれかの値を保持できる識別された共用体を宣言することです。
type SomeValue =
| M of float<m>
| MPS of float<m/s>
次に、通常のパターンマッチングを使用して関数を記述できます。
let convert v =
match v with
| M v -> v / 0.1<m>
| MPS v -> v / 0.2<m/s>
値を識別された共用体の値に明示的にラップする必要がありますが、これを直接(プログラム構造に大きな変更を加えることなく)行う唯一の方法である可能性があります。
int
およびのような通常の型の場合float
、オーバーロードされたメンバー(一部のF#型で宣言されている)を使用することもできますが、F#コンパイラが単位情報を消去した後も署名が同じになるため、測定単位では機能しません。
あなたのアプローチには2つの問題があります。まず、関数の定義でアンダースコアを使用する場合、これは新しい型変数を使用する場合と同じであるため、定義は次のようになります。
let convert (v: float<'u>) = //'
match v with
| :? float<m> -> v / 0.1<m>
| :? float<m/s> -> v / 0.2<m/s>
| _ -> failwith "unknown"
エラーメッセージが示しているのは、コンパイラはそれv
がタイプfloat<'u>
でありfloat<'u>
、適切なサブタイプがないことを認識しているため、タイプテストを実行してそれがfloat<m>
または他のタイプであるかどうかを判断する意味がないということです。
v
最初にオブジェクトにボックス化してから型テストを実行することで、これを回避しようとする場合があります。これは、たとえば、があり、list<'a>
それがであるかどうかを確認したい場合に機能します。これはlist<int>
、ジェネリックオブジェクトに関する完全な型情報が実行時にジェネリック型パラメーターを含めて追跡されるためです(特に、これはJavaのような他のランタイムの動作とは異なります) 。残念ながら、F#の測定単位は実行時に消去されるため、ここでは機能しません-実行時に値が単純であるため、システムが正しい測定タイプを推測する方法はありませんfloat
-F#のシステム測定単位は、Javaが汎用型を処理する方法に関して、実際には非常に似ています。
余談ですが、あなたがやろうとしていることはかなり疑わしいようです-測定単位で一般的な関数は、測定タイプが何であるかに応じて異なることをするべきではありません。それらは適切にパラメトリックである必要があります。正確に何を達成しようとしていますか?確かに、F#のメジャータイプの基礎となる物理的な現実に対応する操作のようには見えません。
http://msdn.microsoft.com/en-us/library/dd233243.aspxの「実行時のユニット」セクションを参照してください。
@kvbに同意します。これを回避する最善の方法は、オブジェクトを渡すことだと思います。
あなたのコード構造を使用して、私がやりたいこと:
let convert (v: float<_>) =
match v with
| :? float<m> -> v<m>
| :? float<inches> -> v * 2.54 / 100.0<m>