我一直在尝试使用更抽象的函数编程概念,例如来自scle的typelevel / cats的概念。
在这种特定情况下,我试图消除在遍历一些map(_.flatten)
之后调用Future
的需要。
使用标准库,它看起来像这样:
def stdExample[T](things: Seq[T]): Future[Seq[T]] = {
Future.traverse(things)(futureMaybeThings[T]).map(_.flatten)
}
def futureMaybeThings[T](thing: T): Future[Option[T]] = ???
我尝试使用来自typelevel / cats的flatTraverse
,但我能得到的最好的是:
def catsExample[T](things: Seq[T]): Future[Seq[T]] = {
things.toList.flatTraverse(futureMaybeThings[T](_).map(_.toList))
}
要获得Traversable,需要调用things.toList
,我可以使用那个。
由于flatTraverse
要求f
为C => G[F[B]]
(C
和B
都为T
,G
为{ {1}}和Future
为F
),List
在没有先使用futureMaybeThings
转换结果的情况下不匹配。这最终比其他解决方案更糟糕。
可以创建一个仅在map(_.toList)
和Future
上运行的函数(因为TraversableOnce
存在隐式转换。这样的实现可能是这样的:
Option[A] => TraversableOnce[A]
现在我的工作方式如下:
def flatTraverse[A, B[_], C, M[X] <: TraversableOnceWithFlatten[X, M]](in: M[A])
(fn: A => Future[B[C]])
(implicit cbf: CanBuildFrom[M[A], B[C], M[B[C]]],
asTraversable: B[C] => TraversableOnce[C],
executor: ExecutionContext): Future[M[C]] = {
Future.traverse(in)(fn).map(_.flatten)
}
有没有办法用typelevel / cats实现同样的事情?
奖金:如果没有,那么这种功能的签名会是什么样的?