Scala 惰性映射求值

Scala 惰性映射求值,scala,concurrency,lazy-evaluation,eager,Scala,Concurrency,Lazy Evaluation,Eager,在Scala中评估贴图基本上有两种选择 惰性计算计算需要下一个值时作为参数传递的函数。如果函数需要一个小时才能执行,那么在需要值时需要等待一个小时。(例如流和迭代器) 当定义映射时,立即求值计算函数。它生成一个新的列表(Vector或其他什么),并存储结果,使程序在这段时间内处于忙碌状态 使用Future我们可以在一个单独的线程中获得列表(Seq或任何内容),这意味着我们的线程不会阻塞,但结果必须存储 所以我做了一些不同的事情 这是很久以前的事了,所以我不记得我是否测试过它。关键是要有一个并

在Scala中评估贴图基本上有两种选择

  • 惰性计算计算需要下一个值时作为参数传递的函数。如果函数需要一个小时才能执行,那么在需要值时需要等待一个小时。(例如
    迭代器
  • 当定义映射时,立即求值计算函数。它生成一个新的列表(
    Vector
    或其他什么),并存储结果,使程序在这段时间内处于忙碌状态
  • 使用
    Future
    我们可以在一个单独的线程中获得列表(
    Seq
    或任何内容),这意味着我们的线程不会阻塞,但结果必须存储
所以我做了一些不同的事情

这是很久以前的事了,所以我不记得我是否测试过它。关键是要有一个并发应用(非阻塞)的映射,并且有点急切地应用于一组元素,填充一个缓冲区(计算机中的核数大小,而不是更多)。这意味着:

  • 对映射的调用不会阻止当前线程
  • 获取元素不会阻塞当前线程(以防之前有时间计算并将结果存储在缓冲区中)
  • 可以处理无限列表,因为我们只预取少数结果(大约8个,取决于核心数)
  • 这一切听起来都很好,你可能想知道问题出在哪里。问题是这个解决方案并不是特别优雅。假设我共享的代码在Java和/或Scala中工作,要迭代映射生成的iterable中的元素,我只需要编写:

    new CFMap(whateverFunction).apply(whateverIterable)
    
    然而,我想写的是:

    whateverIterable.bmap(whateverFunction)
    
    whateverThing.toBuffered.map(whateverFunction)
    
    与Scala中的常见情况一样(“b”表示缓冲),或者类似于:

    whateverIterable.bmap(whateverFunction)
    
    whateverThing.toBuffered.map(whateverFunction)
    
    他们两个都为我工作。所以问题是,我如何在Scala中以惯用的方式做到这一点?一些选择:

    • Monads:创建一个新的集合“Buffered”,这样我就可以使用toBuffered方法(应该作为隐式方法添加到以前的方法中),并实现
      map
      以及这个缓冲对象的所有其他功能(听起来像是相当多的工作)
    • Implicits:创建一个隐式方法,将通常的集合或它们的超类(我不确定应该是哪一个,
      Iterable
      可能?)转换为我可以应用
      .bmap
      方法并从中获取某些内容的其他内容,可能是Iterable
    • 其他:到目前为止,我可能还没有考虑过很多选择。有可能某些库已经实现了这一点(事实上,我会对此感到惊讶,我不敢相信以前没有人想到这一点)。使用已经完成的东西通常是个好主意

    如果有不清楚的地方,请告诉我。

    您要找的是“拉皮条我的书库”模式。请查看:

    object CFMapExtensions {
      import sanity.commons.functional.CFMap
      import scala.collection.JavaConversions._
    
      implicit class IterableExtensions[I](i: Iterable[I]) {
        def bmap[O](f: Function1[I, O]): Iterable[O] = new CFMap(f).apply(asJavaIterable(i))
      }
    
      implicit class JavaIterableExtensions[I](i: java.lang.Iterable[I]) {
        def bmap[O](f: Function1[I, O]): Iterable[O] = new CFMap(f).apply(i)
      }
    
      // Add an implicit conversion to a java function.
      import java.util.function.{Function => JFunction}
      implicit def toJFunction[I, O](f: Function1[I, O]): JFunction[I, O] = {
        new JFunction[I, O]() {
          def apply(t: I): O = f(t)
        }
      }
    }
    
    object Test extends App {
      import CFMapExtensions._
      List(1,2,3,4).bmap(_ + 5).foreach(println)
    }
    

    非常感谢。这个问题没有这个例子那么具体。我将尝试以某种在Scala中可能有意义的方式实现它(问题是缓冲区的易变性)。我向您展示了如何通过扩展Iterable的功能来实现您喜欢的语法。如果我完全没有回答这个问题,我很抱歉。没关系,我想我可以把问题拼凑起来。给我几天时间,找个时间来做这个。再次感谢你。