Ленивая нетерпеливая оценка карты

Есть в основном два варианта оценки карты в Scala.

  • Ленивая оценка компьютеров - функция, которая передается в качестве параметра, когда необходимо следующее значение. Если выполнение функции занимает один час, то ждать часа нужно, чтобы получить значение. (например Stream а также Iterator)
  • Стремительная оценка вычисляет функцию, когда карта определена. Выдает новый список (Vector или что-то еще) и сохраняет результаты, делая программу занятой в это время.
  • С Future мы можем получить список (Seq или что-то еще) в отдельном потоке, это означает, что наш поток не блокируется, но результаты должны быть сохранены.

Так что я сделал что-то другое, пожалуйста, проверьте это здесь.

Это было некоторое время назад, поэтому я не помню, проверял ли я это. Суть в том, чтобы иметь карту, которая применяется одновременно (неблокирующе) и как бы охотно относится к набору элементов, заполняя буфер (размер числа ядер в компьютере и не более). Это означает, что:

  1. Вызов карты не блокирует текущий поток.
  2. Получение элемента не блокирует текущий поток (в случае, если раньше было время его вычислить и сохранить результат в буфере).
  3. Бесконечные списки могут быть обработаны, потому что мы выбираем только несколько результатов (около 8, в зависимости от количества ядер).

Так что все это звучит очень хорошо, и вам может быть интересно, в чем проблема. Проблема в том, что это решение не особенно элегантно ИМХО. Предполагая, что код, которым я поделился, работает в Java и / или Scala, для итерации по элементам в итерируемом, производимом картой, мне нужно только написать:

new CFMap(whateverFunction).apply(whateverIterable)

Однако то, что я хотел бы написать что-то вроде:

whateverIterable.bmap(whateverFunction)

Как обычно в Scala ("b" для буферизованного), или, возможно, что-то вроде:

whateverThing.toBuffered.map(whateverFunction)

Любой из них работает для меня. Итак, вопрос в том, как я могу сделать это идиоматическим способом в Scala? Некоторые варианты:

  • Монады: создайте новую коллекцию "Buffered", чтобы я мог использовать метод toBuffered (который должен быть добавлен к предыдущим как неявный) и реализовать map и все остальное для этой буферизованной вещи (звучит как настоящая работа).
  • Последствия: создайте неявный метод, который преобразует обычные коллекции или их суперкласс (я не уверен, какой он должен быть, Iterable может быть?) к чему-то еще, к которому я могу применить .bmap метод и получить что-то из него, вероятно, итеративный.
  • Другое: вероятно, есть много вариантов, которые я не рассматривал до сих пор. Вполне возможно, что некоторые библиотеки уже реализуют это (я был бы на самом деле удивлен обратным, я не могу поверить, что никто не думал об этом раньше). Использование чего-то, что уже было сделано, обычно является хорошей идеей.

Пожалуйста, дайте мне знать, если что-то неясно.

1 ответ

Решение

То, что вы ищете, это шаблон "pimp-my-library". Проверьте это:

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)
}
Другие вопросы по тегам