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