如何定义和使用具有不可推断类型参数的活动模式?

时间:2011-07-09 16:56:22

标签: f#

我尝试了以下内容:

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

活动模式是否可以具有显式类型参数?如果是这样,我如何定义和使用它们?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:3)

我认为没有办法做你想做的事,因为我认为这没有任何意义。当使用活动模式时,编译器如何推断类型参数?

即,给定

function
| OpAdd x -> ...

编译器如何知道'a应该是什么?

在我看来,你有两种选择。一种是在模式的返回类型中反映'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

另一种方法是在你的模式的一个输入中反映'a(也许是沿着Tomas的回答)。