Сверните бесформенный HList в Future этого же HList, сгладив найденные элементы Future, если таковые имеются - PullRequest
0 голосов
/ 04 апреля 2020

Я пытаюсь преобразовать произвольный HList в Future [HList], где все элементы Future сведены.

Например:

  • Превратить Int :: Future[String] :: HNil в Future[Int :: String :: HNil]
  • Превратить Future[Boolean] :: String :: Int :: HNil в Future[Boolean :: String :: Int :: HNil]

До сих пор мне удавалось реализовать преобразование HList of Futures в Future их результатов, используя foldRight.

import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext, Future}
import shapeless._

object joinFutures extends Poly2 {
  implicit def future[L, R <: HList](implicit ec: ExecutionContext): Case[Future[L], Future[R]] {
    type Result = Future[L :: R]
  } = at[Future[L], Future[R]] { (futureL, futureR) =>
    futureR.flatMap(r => futureL.map(_ :: r))
  }
}

object Example extends App {
  import ExecutionContext.Implicits.global
  import Future.{successful => F}

  type In = Future[Int] :: Future[String] :: Future[Int] :: Future[String] :: HNil
  type Out = Future[Int :: String :: Int :: String :: HNil]
  val in: In = F(1) :: F("asd") :: F(2) :: F("qwe") :: HNil
  val out: Out = in.foldRight(Future.successful(HNil))(joinFutures)
  println(Await.result(out, Duration.Inf)) // 1 :: asd :: 2 :: qwe :: HNil
}

И затем я попытался ввести регистр по умолчанию для моего Poly2, для всех остальных случаев.

object joinFutures extends Poly2 {
  implicit def future[L, R <: HList](implicit ec: ExecutionContext): Case[Future[L], Future[R]] {
    type Result = Future[L :: R]
  } = at[Future[L], Future[R]] { (lFuture, futureR) =>
    futureR.flatMap(r => lFuture.map(_ :: r))
  }
  implicit def default[L, R <: HList](implicit ec: ExecutionContext): Case[L, Future[R]] {
    type Result = Future[L :: R]
  } = at[L, Future[R]] { (l, futureR) =>
    futureR.map(r => l :: r)
  }
}

Но это не удается скомпилировать с ошибкой при вызове foldRight заявив что он не может найти неявное для папки RightFolder[In,Future[HNil.type],joinFutures.type].

Я думаю, проблема в том, что joinFutures теперь имеет конфликтующие случаи, так как элементы HList типа Future соответствуют и future и default case.

Моя цель состояла в том, чтобы сопоставить любой элемент , кроме Futures, но, очевидно, компилятор не может вывести это из приведенного выше кода.

Возможно ли это добиться этого преобразования, используя foldRight вообще? Как?

1 Ответ

0 голосов
/ 04 апреля 2020

Тем временем я нашел решение, поэтому я отвечу на свой вопрос.

Да, этого можно достичь, используя foldRight.

Идея состоит в том, чтобы устранить эту неявную неоднозначность, «переместив неявное неявное определение в суперпризнак с низким приоритетом», как описано в этом выпуске Github .

Вот рабочий пример.

import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext, Future}
import shapeless._

trait joinFuturesDefault extends Poly2 {
  implicit def default[L, R <: HList](implicit ec: ExecutionContext): Case[L, Future[R]] {
    type Result = Future[L :: R]
  } = at[L, Future[R]] { (l, futureR) =>
    futureR.map(r => l :: r)
  }
}

object joinFutures extends joinFuturesDefault {
  implicit def future[L, R <: HList](implicit ec: ExecutionContext): Case[Future[L], Future[R]] {
    type Result = Future[L :: R]
  } = at[Future[L], Future[R]] { (futureL, futureR) =>
    futureR.flatMap(r => futureL.map(_ :: r))
  }
}

object Example extends App {
  import ExecutionContext.Implicits.global
  import Future.{successful => F}

  type In = Int :: Future[String] :: Future[Int] :: String :: HNil
  type Out = Future[Int :: String :: Int :: String :: HNil]
  val in: In = 1 :: F("asd") :: F(2) :: "qwe" :: HNil
  val out: Out = in.foldRight(Future.successful(HNil))(joinFutures)
  println(Await.result(out, Duration.Inf)) // 1 :: asd :: 2 :: qwe :: HNil
}

Таким образом, мы практически поручили компилятору сначала сопоставлять регистры, используя joinFutures, и переходить к регистрам в joinFuturesDefault, только если в joinFutures.

нет совпадений.
...