2010-05-08 88 views
1

在F#我有一个返回System.Linq.Expression实例函数:F#返回类型强制

and System.Object with 
    member this.ToExpression() = 
    match this with 
    | :? System.Int32 -> Expression.Constant(this) :> Expression 
    | :? System.Boolean -> Expression.Constant(this) :> Expression 
    | :? Tml.Runtime.Seq as s -> s.ToExpression() 
    | _ -> failwith "bad expression" 

如果我忽略的回报强制类型转换值F#将推断功能常量表达式的返回类型。我的第一个想法是明确地将返回类型标记为:#Expression,但那不起作用。有没有更好的方法来做到这一点,而不需要手动将返回类型转换为最通用的类​​型?

谢谢。

编辑:感谢所有人的答案。我将使用明确的返回类型+ upcast方案。

回答

4

这里有几个方法,你可能会喜欢:

open System.Linq.Expressions 

type System.Object with 
    member this.ToExpression() : Expression = // explicit 
     match this with 
     | :? System.Int32 -> upcast Expression.Constant(this) // upcast 
     | :? System.Boolean -> Expression.Constant(this) :> _ // _ 
     | _ -> failwith "bad expression" 

通过明确说明在member声明的返回类型,可以进而推断它在体内,如通过_作为“请为我推断这种类型”,或者使用upcast运算符,它将从约束中推断出要上传的类型。

1

我不认为有什么明显更优雅的书写方式,非常幸运。

编译器要求match表达式的所有分支将具有相同的返回类型,并且不会隐式插入任何强制。您可以使用upcast关键字来插入强制而不指定目标类型 - 在这种情况下,编译器将使用其他信息(例如类型注释)来确定类型,并且不必重复类型:

and System.Object with 
    member this.ToExpression() : Expression = 
    match this with 
    | :? System.Int32 -> upcast Expression.Constant(this) 
    | :? System.Boolean -> upcast Expression.Constant(this) 
    | :? Tml.Runtime.Seq as s -> upcast s.ToExpression() 
    | _ -> failwith "bad expression" 

我为每个表达式和类型注释添加了类型注释和upcast,所以F#编译器推断upcast需要强制结果到Expression。当编译器插入隐含的强制唯一的地方是,调用函数,所以你也可以编写以下(但我不知道这是否是更好):

// Thanks to implicit coercions, we don't even need #type 
let expr (a:Expression) = a 

// and then for example: 
| :? System.Int32 -> Expression.Constant(this) |> expr 

出于某种原因,upcast是关键词,所以你不能在流水线中使用它,所以定义这样的函数可能会有一些好处。

1

严格地说,这是不删除coersion但在我看来,这是对眼睛好一点(和将节省您的打字有点太:))

open System.Linq.Expressions 

let Constant obj = Expression.Constant(obj) :> Expression 

type System.Object with 
    member this.ToExpression() 
     match this with 
     | :? System.Int32 -> Constant(this) 
     | :? System.Boolean -> Constant(this) 
     | _ -> failwith "bad expression" 

因为恒类型是一个' - >表达式,它将在两种情况下工作。不利的一面是您必须为您要使用的每个Expression工厂方法定义一个函数。