【问题标题】:F# return type coercionF# 返回类型强制
【发布时间】:2010-05-08 16:40:30
【问题描述】:

在 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 场景。

【问题讨论】:

    标签: f# types coercion type-systems


    【解决方案1】:

    您可能更喜欢以下几种方式:

    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 运算符,该运算符将从约束中推断要向上转换的类型。

    【讨论】:

      【解决方案2】:

      不幸的是,我认为没有比这更优雅的写法了。

      编译器要求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 是一个关键字,因此不能将它与流水线一起使用,因此定义这样的函数可能会有一些好处。

      【讨论】:

        【解决方案3】:

        严格来说,这并没有消除强制,但在我看来,它在视觉上会更好一些(并且也会为您节省一点打字时间:))

        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"
        

        由于 Constant 的类型是 a'->Expression,它在这两种情况下都可以使用。不利的一面是您必须为要使用的每个表达式工厂方法定义一个函数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-07-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-24
          • 2018-01-19
          相关资源
          最近更新 更多