【问题标题】:Can Scala collection's seq/par/view/force be seen as a violation of the uniform return type principle?Scala 集合的 seq/par/view/force 是否可以被视为违反了统一返回类型原则?
【发布时间】:2011-06-17 18:18:53
【问题描述】:

集合框架的大部分实现复杂性源于这样一个事实,即 Scala 可以(与 C# 的 LINQ 或其他集合框架不同)为高阶函数返回“最佳”集合类型:

val numbers = List(1,2,3,4,5)
numbers map (2*) // returns a List[Int] = List(2, 4, 6, 8)

val doubles = Array(1.0, 2.0, 3.0)
doubles filter (_ < 3) // returns Array[Double] = Array(1.0, 2.0)

为什么这个原则不适用于seqparviewforce 等方法?

numbers.view.map(2*).force 
// returns Seq[Int] = List(2, 4, 6, 8)

numbers.seq 
// returns scala.collection.immutable.Seq[Int] = List(1, 2, 3, 4)

doubles.par.seq 
// returns scala.collection.mutable.ArraySeq[Double] = ArraySeq(1.0, 2.0, 3.0)

是否存在阻止其工作的技术限制? 或者这是设计/意图? 考虑到 LINQ 基本上是惰性的,Scala 的等价物(viewforce)并不是更安全(仅在使用严格方法时),对吧?

【问题讨论】:

    标签: c# linq scala collections types


    【解决方案1】:

    可以将更多类型信息嵌入到并行集合类中,这样您就可以取回开始时的集合,这是真的。这意味着在通过调用par(在 O(n) 中,因为元素被复制到向量中)然后调用seqList 转换为ParVector 之后,您将再次获得List .要使用seq 获取列表,您必须将向量中的所有元素复制回列表中。相反,发生的是:

    • ParVector 在调用 seq 时被转换回 Vector - 它在 O(1) 中转换
    • 在此向量上再次调用 par 将在 O(1) 中为您提供 ParVector,因为它们都向量和并行向量共享相同的基础数据

    注意,像列表这样的集合在变成并行集合时必须进行重组,否则对它的操作不能有效地并行化。

    因此,您无需在致电parseq 时重复为复制付费 - 转换变得更加高效。由于并行收集的主要目标是提高效率,因此这被认为比统一返回类型原则更重要。

    【讨论】:

    • lazy/view 呢?是否存在类似的问题?例如。为什么Vector(1,2,3).view.map(2*).force 会返回Seq[Int] = Vector(2, 4, 6)
    • 在我的脑海中,这应该是由于map - 当SeqView 伴随对象中的隐式CanBuildFrom 得到解析时,类型信息丢失。我的猜测是canBuildFrom 方法可以改进为采用额外的类型参数ForcedCollection 并将其放入CanBuildFrom - SeqView[A, ForcedCollection] 的目标类型而不是SeqView[A, Seq[_]]。不过,我还没有玩过这个看看它是否有效。
    【解决方案2】:

    关于集合方法的静态返回类型,C# 支持重载 LINQ 扩展方法(SelectWhere 等),并会自动选择范围内最具体的方法。所以Seq.Select 可以返回SeqEnumerable.Select 可以返回Enumerable 等等。这与Scala 中选择最具体的隐式实现的方式非常相似。

    关于动态类型,LINQ 操作是作为扩展方法实现的,因此不会执行动态分派。因此,(Seq as Enumerable).Select 将返回 Enumerable,而不是 Seq。在 Scala 中,集合方法调用是动态分派的,因此mapfilter 等的动态类型将保持不变。这两种方法各有优缺点。此类问题的唯一干净解决方案是多方法恕我直言,两种语言/运行时都不能有效地支持它们。

    至于运行时行为,LINQ 总是返回一个惰性求值的集合视图。视图上没有方法可以神奇地返回原始类型的集合,您必须手动指定您想要一个数组,例如使用 toArray 方法。恕我直言,这是一种比 Scala 中的方法更干净、更简单的方法,并且惰性集合操作比严格集合操作组合得更好,但这是以额外的方法调用为代价来为单个集合操作获取严格集合的。

    【讨论】:

    • 我认为动态类型的问题在于 C# 的类型系统不足以计算它。提供与 Scala 相同的功能需要为每个集合类定义和实现具有正确返回类型的每个方法。这在 C#(或 Java)中是不实用的。
    猜你喜欢
    • 2017-03-23
    • 1970-01-01
    • 2014-02-15
    • 2010-11-29
    • 2011-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多