gpt4 book ai didi

scala - 使用Shapeless通过HList将Future的tuple转换为tuple的Future

转载 作者:行者123 更新时间:2023-12-02 01:47:50 24 4
gpt4 key购买 nike

是否有一种简单的方法可以将 (Future[A], Future[B], Future[C], ..., Future[N]) 类型的元组转换为 Future[(A, B, C, . ..,N)]?这假设元组中元素的数量未定义。

我尝试将元组转换为 HList,并尝试了类似的 FoldLeft 技巧并进行理解,如 Future.sequence 中所做的那样,但在处理传递到折叠中的类型时没有运气。尝试使用递归函数进行相同的操作。但由于缺少 HList.head、HList.tail,这段代码仍然无法编译。代码如下:

def sequence[L <: HList](in: L)(implicit ihc: IsHCons[L]) = {

val list = for (i <- in.head; j <- in.tail.head) yield HList(i, j)

@tailrec
def sequence2(fList: Future[HList], listF: HList): Future[HList] = {
if (listF == HNil) fList
else {
val nextFList = for (l <- fList; e <- listF.head.asInstanceOf[Future[_]]) yield l :+ e
sequence2(nextFList, listF.tail)
}
}

sequence2(list, in.tail.tail)
}

此代码应返回 Future[HList],然后我们可以使用 tupled 函数将其映射回元组。理想情况下,我们需要检查元组中的元素是否少于 3 个。但对于本练习,我们假设输入是大小为 3 或更大的 HList。

我使用的是 Shapeless 1.2.4,但由于其他依赖项而无法移动。

提前致谢!

最佳答案

不知道这是否算“简单”,但是Dan Lien我正在讨论如何对 Option 的元组进行排序 just the other day ,和 my solution对于这种情况,可以直接适应 Future (请注意,我正在使用 scalaz-contrib 的 monad 实例来实现 Future;如果您使用的是 Scalaz 7.1,则此没有必要):

import scala.concurrent.{ ExecutionContext, Future }
import scalaz._, Scalaz._, contrib.std.scalaFuture._
import shapeless._, ops.hlist.{ RightFolder, Tupler }

// Might as well stay generic in `F` for this part.
object applicativeFolder extends Poly2 {
implicit def caseApplicative[A, B <: HList, F[_]](implicit
app: Applicative[F]
) = at[F[A], F[B]] {
(a, b) => app.ap(a)(app.map(b)(bb => (_: A) :: bb))
}
}

// It should be possible to make this part generic in `F` as well,
// but type inference makes it tricky, so we specialize to `Future`.
def sequence[T, EL <: HList, L <: HList, OL <: HList, OT](t: T)(implicit
executor: ExecutionContext,
gen: Generic.Aux[T, EL],
eq: EL =:= L,
folder: RightFolder.Aux[L, Future[HNil], applicativeFolder.type, Future[OL]],
tupler: Tupler.Aux[OL, OT]
): Future[OT] =
eq(gen.to(t)).foldRight(Future.successful(HNil: HNil))(applicativeFolder).map(
tupler(_)
)

哦,刚刚注意到您使用的是 1.2.4。必要的改变本质上是机械性的——像下面这样的东西应该有效:

// It should be possible to make this part generic in `F` as well,
// but type inference makes it tricky, so we specialize to `Future`.
def sequence[T, L <: HList, OL <: HList, OT](t: T)(implicit
executor: ExecutionContext,
hlister: HListerAux[T, L],
folder: RightFolderAux[L, Future[HNil], applicativeFolder.type, Future[OL]],
tupler: TuplerAux[OL, OT]
): Future[OT] =
t.hlisted.foldRight(Future.successful(HNil: HNil))(applicativeFolder).map(
tupler(_)
)

它的工作原理如下:

scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global

scala> val result = sequence((Future(1), Future('a)))
result: scala.concurrent.Future[(Int, Symbol)] = ...

scala> result.foreach(println)
(1,'a)

请注意,shapeless-contrib 中有一个 sequence 实现,但由于各种原因(涉及类型推断),在这种情况下很难使用。

关于scala - 使用Shapeless通过HList将Future的tuple转换为tuple的Future,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23453570/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com