不知道這是否算作「簡單」,但Dan Lien和我討論如何序列Option
小號just the other day元組,並my solution對於這種情況下,可以被直接用於爲Future
(工作注意,我使用Future
scalaz-contrib的單子實例;如果你在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
實現,但由於種種原因(包括類型推理)在這種情況下很難使用。
'caseApplicative'的類型是'F [A :: B]'? – pedrofurla
是的,但在'Case'包裝中。 –
試一試。也許我不完整。 hlisted不可用於類型T.爲了允許t的隱式轉換,我必須使用def序列[T <:Product,L <:HList ...不確定它甚至是正確的。 – akara