2011-07-09 3 views
3

私は次のことを試してみました:推論不可能なタイプの引数を持つアクティブなパターンを定義して使用するにはどうすればよいですか?

let inline (|OpAdd|_|) (aty:Type, x:obj, y:obj) = 
    if aty.Equals(typeof<'a>) then Some(box ((unbox<'a> x) + (unbox<'a> y))) 
    else None 

//FSI given signature: 
//val inline (|OpAdd|_|) : Type * obj * obj -> obj option 

何の警告やエラーを与えていないが、私は、コールサイトで明示的な型の引数を渡す方法を見つけ出すことはできません、'aは常にintと推察されていることを思われます。

私は定義の中で明示的なパラメータを配置しようとすると、私はカップルの警告とエラーが出る:

let inline (|OpAdd|_|)<'a> (aty:Type, x:obj, y:obj) = 
    if aty.Equals(typeof<'a>) then Some(box ((unbox<'a> x) + (unbox<'a> y))) 
    else None 

warning FS1189: Type parameters must be placed directly adjacent to the type name, e.g.  "type C<'T>", not  type "C <'T>" 

error FS0001: The declared type parameter 'a' cannot be used here since the type parameter cannot be resolved at compile time 

は、それが可能なアクティブなパターンは、明示的な型パラメータを持っているためですか?もしそうなら、私はそれらをどのように定義して使用するのですか?

答えて

4

これを行うためのきれいな方法があるかどうかはわかりません(おそらくそうではありませんが、間違いかもしれません)。

ダミーの回避策として、'T(作成しやすい値を持つプリミティブ型の場合)またはExpr<'T>(実際にインスタンスを作成したくない場合)のダミーパラメータを追加できます。 。その後、型を指定し、いくつかのダミーパラメータとパターンを使用することができます。

let inline (|OpAdd|_|) (e:Expr<'T>) (aty:Type, x:obj, y:obj) = 
    if aty.Equals(typeof<'T>) then Some(box ((unbox<'T> x) + (unbox<'T> y))) 
    else None 

let dummy<'T> : 'T = failwith "!" 

match (typeof<float>, box 1.1, box 2.1) with 
| OpAdd <@ dummy<int> @> res -> res 
| OpAdd <@ dummy<float> @> res -> res 
| _ -> null 
+0

不快ですが、動作します! –

3

私はそれが本当に理にかなっているとは思わないので、私はあなたが欲しいものを行うにはどのような方法はないと思います。アクティブなパターンが使用されているとき、コンパイラはどのように型引数を推測しますか?

コンパイラは'aがどうあるべきかを知っているだろうか

function 
| OpAdd x -> ... 

与えられた、ありますか?

私はそれを見ると、2つの選択肢があります。一つは、あなたのパターンの戻り値の型に'aを反映するために、次のとおりです。

let inline (|OpAdd|_|) (aty:System.Type, x:obj, y:obj) = 
    if aty.Equals(typeof<'a>) then Some((unbox<'a> x + unbox<'a> y) : 'a) 
    else None 

let (OpAdd(x:int)) = typeof<int>, box 1, box 2 
let (OpAdd(y:float)) = typeof<float>, box 3.0, box 4.0 

他の(おそらくトーマスの答えの線に沿って)あなたのパターンへの入力のうちの1つで'aを反映しています。

+2

私はあなたが 'function | OpAdd x - > ... 'が、構文上有効ではありません。 –

+0

@Tomas:yup、ちょうど –

+0

@kvb - 私は実際に戻り値の型をジェネリック(そしてボクシング)にするアプローチを使用していますが、私は@Tomasにチェックマークを付けました。贅沢。 –

関連する問題