This commit is contained in:
Timofey Khoruzhii 2023-04-16 14:22:36 +03:00
parent 0ac8e6ff3a
commit f68fea8496

View file

@ -3,56 +3,61 @@ package mipt.homework8
import scala.concurrent.{ExecutionContext, Future}
import mipt.utils.Homeworks._
import scala.util.{Failure, Success}
object Task1 {
def foldF[A, B](in: Seq[Future[A]], zero: B, op: (B, A) => B)(
implicit executionContext: ExecutionContext
): Future[B] =
task"""
Реализуйте функцию, которая выполнит свертку (fold) входящей последовательности из Future,
используя переданный комбинатор и начальное значение для свертки.
Если какая-либо из исходных Future зафейлилась, то должна вернуться ошибка от нее
""" (1, 1)
): Future[B] = in.foldLeft(Future.successful(zero)) { (acc, futureA) =>
for {
a <- futureA
b <- acc
} yield op(b, a)
}
def flatFoldF[A, B](in: Seq[Future[A]], zero: B, op: (B, A) => Future[B])(
implicit executionContext: ExecutionContext
): Future[B] =
task"""
Реализуйте функцию, которая выполнит свертку (fold) входящей последовательности из Future,
используя переданный асинхронный комбинатор и начальное значение для свертки.
Если какая-либо из исходных Future зафейлилась, то должна вернуться ошибка от нее.
Если комбинатор зафейлился, то должна вернуться ошибка от него.
""" (1, 2)
): Future[B] = in.foldLeft(Future.successful(zero)) { (acc, futureA) =>
for {
a <- futureA
b <- acc
res <- op(b, a)
} yield res
}
def fullSequence[A](futures: List[Future[A]])(
implicit ex: ExecutionContext
): Future[(List[A], List[Throwable])] =
task"""
В данном задании Вам предлагается реализовать функцию fullSequence,
похожую на Future.sequence, но в отличии от нее,
возвращающую все успешные и не успешные результаты.
Возвращаемое тип функции - кортеж из двух списков,
в левом хранятся результаты успешных выполнений,
в правово результаты неуспешных выполнений.
Не допускается использование методов объекта Await и мутабельных переменных var
""" (1, 3)
def fullSequence[A](futures: List[Future[A]])(implicit ex: ExecutionContext): Future[(List[A], List[Throwable])] = {
Future
.traverse(futures) { future =>
future.transform {
case Success(value) => Success((Some(value), None))
case Failure(exception) => Success((None, Some(exception)))
}
}
.map { results =>
val (successes, failures) = results.partition(_._1.isDefined)
(
successes.flatMap(_._1),
failures.flatMap(_._2)
)
}
}
def traverse[A, B](in: List[A])(fn: A => Future[B])(
implicit ex: ExecutionContext
): Future[List[B]] =
task"""
Реализуйте traverse c помощью метода Future.sequence
""" (1, 4)
): Future[List[B]] = Future.sequence(in.map(fn))
def mapReduce[A, B, B1 >: B](in: List[A], map: A => Future[B], reduce: (B1, B1) => B1)(
implicit ex: ExecutionContext
): Future[B1] =
task"""
Реализуйте алгоритм map/reduce.
Исходный список обрабатывается параллельно (конкурентно) с помощью применения функции map к каждому элементу
Результаты работы функции map должны быть свернуты в одно значение функцией reduce
Если в ходе выполнения какой-либо операции возникло исключение - эту обработку нужно игнорировать
Если ни один вызов map не завершился успешно, вернуть зафейленную фьючу с исключением UnsupportedOperationException
""" (1, 5)
): Future[B1] = {
val mapped = in.map(a => map(a).transform(result => Success(result.toOption)))
fullSequence(mapped).flatMap {
case (successes, _) =>
successes.flatten match {
case head :: tail => Future.successful(tail.foldLeft(head: B1)(reduce))
case Nil => Future.failed(new UnsupportedOperationException("No successful map operation"))
}
}
}
}