【问题标题】:Upcasting in F# with sequences在 F# 中使用序列向上转换
【发布时间】:2013-11-19 14:19:44
【问题描述】:

我正在尝试使用 F# 中的表达式(System.Linq.Expression 类型)。这是我遇到的问题的一个简单示例:

let blah = seq {
    yield Expression.New(typedefof<'T>)
    yield Expression.Constant(1)
}

我希望blah 成为seq&lt;Expression&gt;。然而,该序列通过第一个产量推断其类型,即NewExpression。这将导致第二个 yield 导致编译失败,因为它是 ConstantExpression。一个可行的解决方案是向上转换所有收益:

let blah = seq<Expression> {
    yield Expression.New(typedefof<'T>) :> Expression
    //or
    yield upcast Expression.Constant(1)
}

但这感觉很笨拙,每次都必须向上转换。我认为灵活的类型也可能是一个可能的解决方案,但我也遇到了麻烦。 seq&lt;#Expression&gt; 似乎不起作用。

有没有一种方法可以生成一系列表达式而不必向上转换每个表达式?

【问题讨论】:

  • F# 在大多数情况下不会隐式向上转换,所以我不认为向上转换关键字笨拙,但我也不知道是否有不同的方法。
  • 我认为this question 也涵盖了您的情况,特别是如果您不需要序列 但可以使用数组或列表,您可以添加a type annotation and it should work。 ..
  • 虽然这是一个简单的示例,但使用序列对我来说有其优势,因为我将使用yield!,但也许列表是一个可行的解决方案。这个答案也帮助我理解了为什么 F# 编译器对这个主题有点好笑。
  • 一个更易读的变体:let blah = seq&lt;Expression&gt; { yield Expression.New(typedefof&lt;'T&gt;) :&gt; _ ; yield Expression.Constant(1) :&gt; _ }

标签: f#


【解决方案1】:

正如其他人已经提到的,F# 通常不会在您的代码中自动插入向上转换,因此您需要添加类型注释和转换或 upcast 关键字 - 我认为 cmets 已经涵盖了所有选项。

编译器进行向上转换有两种情况——一种是向函数传递参数时,另一种是创建数组或列表文字时。第二个实际上可以用来简化您的示例:

let blah<'T> : Expression list = 
  [ Expression.New(typedefof<'T>) 
    Expression.Constant(1) ]

在这里,编译器自动插入向上转换到Expression。我想你的实际用例更复杂 - 当你需要带有 yield 的序列表达式时,这将不起作用,因为你正在编写 sequence expresions 而不是 list literals

【讨论】:

  • 感谢您的回答。 “灵活类型”是否适合这里的任何地方?
猜你喜欢
  • 2015-08-09
  • 1970-01-01
  • 1970-01-01
  • 2013-08-23
  • 1970-01-01
  • 2010-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多