对Scala可变集合的观点有什么懒惰?

时间:2019-05-26 19:50:11

标签: scala collections lazy-evaluation lazy-sequences

我认为这个问题本质上是关于可变性中的懒惰。

Scala编程(或the docs)中,他们提供了有关如何在不可变和可变集合上使用视图的示例。在该部分中,他们声明

  

[ transformer 方法]将至少一个集合作为其接收者对象,并在其结果中产生另一个集合。 ... view 是一种特殊的集合,它代表一些基本集合,但是懒惰地实现了所有的转换器。

他们给出了具有不变集合的示例,我了解那里的懒惰是如何工作的。但是我在懒惰在可变集合的示例中扮演的角色很挣扎:

  

[在可变序列上的视图]上的许多转换器功能为原始序列提供了一个窗口...示例...

1) Solving TestCase-01.dat...
 - UB = 48, LB = 48
 - Status = 2
 - Solve Time = 1.299999952 sec
  

该视图不会复制这些元素,而只是提供对它们的引用。

val arr = (0 to 9).toArray
val subarr = arr.view.slice(3, 6)

我理解为什么我们会得到这个答案。但是,关于变压器def negate(xs: collection.mutable.Seq[Int]) = for (i <- 0 until xs.length) xs(i) = - xs(i) negate(subarr) arr // Array(0, 1, 2, -3, -4, -5, 6, 7, 8, 9) 的懒惰是什么?我已经理解惰性是指仅在需要时才计算值(例如不可变集合示例)。但是slice中的值从未被计算过,它们只是对slice中的值的引用,即使在调用arr之后也是如此。这是我对懒惰的误解吗?还是文档以另一种方式使用懒惰?还是其他?

2 个答案:

答案 0 :(得分:1)

此示例显示了slice中的惰性内容:

val arr = (0 to 9).toArray

val subarrLazy = arr.view.map(x=>{println(x+1);x+1}).slice(3, 6)
//nothing printed

subarrLazy.force
//prints 1 2 3 ...

subarrLazy(0)
//prints: 3

subarrLazy产生的map中的值将仅按需计算。

编辑:

正如我现在看到的,在使用arr.view.slice(3, 6)的情况下,没有什么要计算的,而且懒惰甚至不用于值计算,因此,在使用map的情况下,slice只返回可变的seq而不是view +切片。但是此序列仍然是按需延迟执行切片的惰性操作的包装。

val a: SeqView[Int, Array[Int]] = arr.view.map(x=>{println(x);x}).slice(3, 6)
val b: mutable.Seq[Int] = arr.view.slice(3, 6)

所以我们可以说涉及两种惰性:1.值计算上的惰性2.变压器上的惰性。不幸的是,我不知道这些类型的正式名称以及它们之间的关系。我猜想#1只是函子延迟映射其值的一种特例(例如IO monad),而#2是延迟链模式或类似的东西。

这两种模式都与可变性无关。

答案 1 :(得分:0)

这是这种懒惰行为的一个更好的例子:

val a = Array(1,2,3)
val b = a.map(_ + 5)
val c = a.view.map(_ + 5)
println(b(1)) //prints 7
println(c(1)) // prints 7

a(1) = 5

println(b(1)) // still prints 7, since that array was computed on instantiation
println(c(1)) // now prints 10, since elements of c are lazily evaluated each time.