Scala 视图——非严格与惰性
Scala views -- non-strict vs. lazy
我正在尝试创建一个 "lazy" 对象图(实际上,它们是演员,但我用一个更简单的例子来问我的问题)。
从某种意义上说,Scala 视图是惰性。但他们的懒惰实际上只是不严格。也就是说,这些值实际上是按名称调用的,这反过来又表示在需要时通过调用 Function0(无参数函数)来评估这些值.
我感兴趣的是延迟计算但只计算一次的集合。这是我正在寻找的东西:
val x = Map(1->2, 2->2).view
val y = x map {case (k,v) => (k,{println("Hello");v.toString})}
val z1 = y.find{case (k,_) => k==1}
val z2 = y.find{case (k,_) => k==1}
当我将其放入 Scala 工作表中时,我得到的是:
x: scala.collection.IterableView[(Int, Int),scala.collection.immutable.Map[Int,Int]] = IterableView(...)
y: scala.collection.IterableView[(Int, String),Iterable[_]] = IterableViewM(...)
Hello
z1: Option[(Int, String)] = Some((1,1))
Hello
z2: Option[(Int, String)] = Some((1,1))
一切都是应该的。除了我不想看到第二个 "Hello"。换句话说,我只希望在需要时调用映射函数 (toString)。
有没有人对如何实现我的目标有建议?这不是特别重要,但我很好奇它是否可以完成。
我会提出替代解决方案,而不是 laziness
。
如果您的 v
将发挥作用但没有价值怎么办?
在这种情况下,您可以在需要时控制执行,而无需依赖集合惰性...
val y = x map {case (k,v) => (k,() => {println("Hello");v.toString})}
你可以几乎使用 Stream
:
得到你想要的
scala> val x = TreeMap(1->2, 2->2) // to preserve order
x: scala.collection.immutable.TreeMap[Int,Int] = Map(1 -> 2, 2 -> 2)
scala> val y = x.toStream map {case (k,v) => (k,{println(s"Hello $k");v.toString})}
Hello 1
y: scala.collection.immutable.Stream[(Int, String)] = Stream((1,2), ?)
scala> y.find{case (k,_) => k==1}
res8: Option[(Int, String)] = Some((1,2))
scala> y.find{case (k,_) => k==2}
Hello 2
res9: Option[(Int, String)] = Some((2,2))
如你所见,第一个元素被严格评估,但其他元素按需评估和记忆
如果您将流本身设为 lazy val
,您会得到想要的:
scala> val x = TreeMap(1->2, 2->2) // to preserve order
x: scala.collection.immutable.TreeMap[Int,Int] = Map(1 -> 2, 2 -> 2)
scala> lazy val y = x.toStream map {case (k,v) => (k,{println(s"Hello $k");v.toString})}
y: scala.collection.immutable.Stream[(Int, String)] = <lazy>
scala> y.find{case (k,_) => k==1}
Hello 1
res10: Option[(Int, String)] = Some((1,2))
scala> y.find{case (k,_) => k==1}
res11: Option[(Int, String)] = Some((1,2))
如果你不介意在使用时立即评估整个集合,你只需要一个惰性val并且集合可以保持原样(地图,列表等等)
val x = TreeMap(1->2, 2->2)
lazy val y = x map {case (k,v) => (k,{println(s"Hello $k");v.toString})}
我不认为你可以有一张(真正的)惰性地图,但如果有人证明我错了,我会很高兴:)
编辑:
您可以通过像这样包装您的值来拥有(某种)惰性地图:
class Lazy[T](x: => T) {
lazy val value = x
override def toString = value.toString
}
object Lazy {
implicit def toStrict[T](l: Lazy[T]): T = l.value
}
val x = TreeMap(1->2, 2->2)
lazy val y = x map {case (k,v) => (k, new Lazy({println(s"Hello $k");v.toString}))}
y.find{case (k,v) => v.indexOf("x");k==1} // let's use v to evaluate it, otherwise nothing gets printed
y.find{case (k,v) => v.indexOf("x");k==1}
隐式转换允许您像使用原始类型一样使用您的值
我不知道有哪个合集 API 能提供那种懒惰。但是,我认为您可以按照 here:
中描述的函数记忆来实现您想要的
case class Memo[I <% K, K, O](f: I => O) extends (I => O) {
import collection.mutable.{Map => Dict}
val cache = Dict.empty[K, O]
override def apply(x: I) = cache getOrElseUpdate (x, f(x))
}
val x = Map(1->2, 2->2).view
val memo = Memo { v: Int =>
println("Hello")
v.toString
}
val y = x.map { case (k, v) =>
(k, memo(v))
}
val z1 = y.find{case (k,_) => k==1}
val z2 = y.find{case (k,_) => k==1}
输出:
Hello
z1: Option[(Int, String)] = Some((1,2))
z2: Option[(Int, String)] = Some((1,2))
我正在尝试创建一个 "lazy" 对象图(实际上,它们是演员,但我用一个更简单的例子来问我的问题)。
从某种意义上说,Scala 视图是惰性。但他们的懒惰实际上只是不严格。也就是说,这些值实际上是按名称调用的,这反过来又表示在需要时通过调用 Function0(无参数函数)来评估这些值.
我感兴趣的是延迟计算但只计算一次的集合。这是我正在寻找的东西:
val x = Map(1->2, 2->2).view
val y = x map {case (k,v) => (k,{println("Hello");v.toString})}
val z1 = y.find{case (k,_) => k==1}
val z2 = y.find{case (k,_) => k==1}
当我将其放入 Scala 工作表中时,我得到的是:
x: scala.collection.IterableView[(Int, Int),scala.collection.immutable.Map[Int,Int]] = IterableView(...)
y: scala.collection.IterableView[(Int, String),Iterable[_]] = IterableViewM(...)
Hello
z1: Option[(Int, String)] = Some((1,1))
Hello
z2: Option[(Int, String)] = Some((1,1))
一切都是应该的。除了我不想看到第二个 "Hello"。换句话说,我只希望在需要时调用映射函数 (toString)。
有没有人对如何实现我的目标有建议?这不是特别重要,但我很好奇它是否可以完成。
我会提出替代解决方案,而不是 laziness
。
如果您的 v
将发挥作用但没有价值怎么办?
在这种情况下,您可以在需要时控制执行,而无需依赖集合惰性...
val y = x map {case (k,v) => (k,() => {println("Hello");v.toString})}
你可以几乎使用 Stream
:
scala> val x = TreeMap(1->2, 2->2) // to preserve order
x: scala.collection.immutable.TreeMap[Int,Int] = Map(1 -> 2, 2 -> 2)
scala> val y = x.toStream map {case (k,v) => (k,{println(s"Hello $k");v.toString})}
Hello 1
y: scala.collection.immutable.Stream[(Int, String)] = Stream((1,2), ?)
scala> y.find{case (k,_) => k==1}
res8: Option[(Int, String)] = Some((1,2))
scala> y.find{case (k,_) => k==2}
Hello 2
res9: Option[(Int, String)] = Some((2,2))
如你所见,第一个元素被严格评估,但其他元素按需评估和记忆
如果您将流本身设为 lazy val
,您会得到想要的:
scala> val x = TreeMap(1->2, 2->2) // to preserve order
x: scala.collection.immutable.TreeMap[Int,Int] = Map(1 -> 2, 2 -> 2)
scala> lazy val y = x.toStream map {case (k,v) => (k,{println(s"Hello $k");v.toString})}
y: scala.collection.immutable.Stream[(Int, String)] = <lazy>
scala> y.find{case (k,_) => k==1}
Hello 1
res10: Option[(Int, String)] = Some((1,2))
scala> y.find{case (k,_) => k==1}
res11: Option[(Int, String)] = Some((1,2))
如果你不介意在使用时立即评估整个集合,你只需要一个惰性val并且集合可以保持原样(地图,列表等等)
val x = TreeMap(1->2, 2->2)
lazy val y = x map {case (k,v) => (k,{println(s"Hello $k");v.toString})}
我不认为你可以有一张(真正的)惰性地图,但如果有人证明我错了,我会很高兴:)
编辑: 您可以通过像这样包装您的值来拥有(某种)惰性地图:
class Lazy[T](x: => T) {
lazy val value = x
override def toString = value.toString
}
object Lazy {
implicit def toStrict[T](l: Lazy[T]): T = l.value
}
val x = TreeMap(1->2, 2->2)
lazy val y = x map {case (k,v) => (k, new Lazy({println(s"Hello $k");v.toString}))}
y.find{case (k,v) => v.indexOf("x");k==1} // let's use v to evaluate it, otherwise nothing gets printed
y.find{case (k,v) => v.indexOf("x");k==1}
隐式转换允许您像使用原始类型一样使用您的值
我不知道有哪个合集 API 能提供那种懒惰。但是,我认为您可以按照 here:
中描述的函数记忆来实现您想要的case class Memo[I <% K, K, O](f: I => O) extends (I => O) {
import collection.mutable.{Map => Dict}
val cache = Dict.empty[K, O]
override def apply(x: I) = cache getOrElseUpdate (x, f(x))
}
val x = Map(1->2, 2->2).view
val memo = Memo { v: Int =>
println("Hello")
v.toString
}
val y = x.map { case (k, v) =>
(k, memo(v))
}
val z1 = y.find{case (k,_) => k==1}
val z2 = y.find{case (k,_) => k==1}
输出:
Hello
z1: Option[(Int, String)] = Some((1,2))
z2: Option[(Int, String)] = Some((1,2))