F#返回类型强制

时间:2010-05-08 16:40:31

标签: f# types coercion type-systems

在F#中,我有一个返回System.Linq.Expression实例的函数:

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#会将函数的返回类型推断为ConstantExpression。我的第一个想法是明确地将返回类型标记为:#Expression,但这不起作用。有没有更优雅的方法,不涉及手动将返回类型转换为最通用的类​​型?

感谢。

编辑:感谢各位的回答。我将使用显式返回类型+ upcast场景。

3 个答案:

答案 0 :(得分: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 :(得分: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是一个关键字,因此您无法将其用于流水线操作,因此定义此类函数可能会带来一些好处。

答案 2 :(得分:1)

严格来说,这并不能消除这种情绪,但在我看来,眼睛看起来更好一点(并且会节省你一点点的打字:))

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工厂方法定义一个函数。