Ленивая нетерпеливая оценка карты
Есть в основном два варианта оценки карты в Scala.
- Ленивая оценка компьютеров - функция, которая передается в качестве параметра, когда необходимо следующее значение. Если выполнение функции занимает один час, то ждать часа нужно, чтобы получить значение. (например
Stream
а такжеIterator
) - Стремительная оценка вычисляет функцию, когда карта определена. Выдает новый список (
Vector
или что-то еще) и сохраняет результаты, делая программу занятой в это время. - С
Future
мы можем получить список (Seq
или что-то еще) в отдельном потоке, это означает, что наш поток не блокируется, но результаты должны быть сохранены.
Так что я сделал что-то другое, пожалуйста, проверьте это здесь.
Это было некоторое время назад, поэтому я не помню, проверял ли я это. Суть в том, чтобы иметь карту, которая применяется одновременно (неблокирующе) и как бы охотно относится к набору элементов, заполняя буфер (размер числа ядер в компьютере и не более). Это означает, что:
- Вызов карты не блокирует текущий поток.
- Получение элемента не блокирует текущий поток (в случае, если раньше было время его вычислить и сохранить результат в буфере).
- Бесконечные списки могут быть обработаны, потому что мы выбираем только несколько результатов (около 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)
}