在Scala中将(未来的清单)转换为(未来的清单)

时间:2018-08-03 19:10:41

标签: scala monads future

我在一个Scala宠物项目中遇到一种情况,我真的不知道该如何克服。

以下示例显示了我的问题。

myscript.exe

我希望this_file = os.path.realpath(__file__) src = this_file filenameOnly, file_extension = os.path.splitext(src) exeFile = filenameOnly+'.exe' print ('exe file to check', exeFile) if os.path.exists(exeFile): src = exeFile print ('Binary file', src) 返回.exe,但我不知道该怎么做,因为.py的类型为 Application.OpenURL("whatsapp://send?phone=9999878653&text=[hello]"); ,这很有意义。

有办法吗?一个朋友告诉我“这就是Cats的目的”,但这是唯一的选择,我的意思是,我不能仅使用Scala核心库中的内容吗?

谢谢。

3 个答案:

答案 0 :(得分:4)

在您的Future.sequence上使用List[Future[???]]来制作Future[List[???]]

val listOfFuture: List[Future[???]] = ???

val futureList: Future[List[???]] = Future.sequence(listOfFuture)

答案 1 :(得分:2)

因此,val eithers = Future.traverse(myLists)(createList)将给您Future[List[Either[ErrorCreatingList, MyList]]]

您现在可以将其转换为所需的格式,但这取决于您要如何处理错误。如果某些请求返回错误,而其他请求成功,该怎么办?

如果一切成功,则此示例返回Right[List[MyList]],否则返回Left并返回第一个错误:

type Result = Either[ErrorCreatingList, List[MyList]]
val result: Future[Result] = eithers.map { 
   _.foldLeft[Result](Right(Nil)) { 
     case (Right(list), Right(myList)) => Right(myList :: list)
     case (x @ Left(_), _) => x
     case (_, Left(x)) => Left(x)
  }.right.map(_.reverse)
}

我不是cats专家,但我认为唯一有用的是不必在结尾的.right之前键入.map ...但是scala 2.12做到了默认也是。

还有一个名为scalactic的库,它添加了一些有趣的功能,使您可以将多个错误组合在一起……但是您必须在右边具有错误才能起作用……这会与几乎所有其他东西都不兼容。我不得不说,如果必须要“手动”合并这些错误,我会这样做,而不是切换到标度,这不仅不兼容,而且学习曲线很大,而且会损害可读性。

答案 2 :(得分:2)

在这里,人们可以很快看到“ scala-cats中已经一定有这样的东西”:

  • Future是单子
  • Future[Either[E, ?]]本质上是EitherT[E, Future, ?],因此它也是一个monad
  • 每个Monad自动都是一个Applicative
  • 因此,M[X] = EitherT[E, Future, X]Applicative
  • 对于每个适用的A和可遍历的T,将T[A[X]]交换为A[T[X]]都是很简单的。
  • List有一个Traverse实例
  • 您应该可以使用Traverse[List]List[EitherT[E, Future, X]]EitherT[E, Future, List[X]]
  • 从那里到达Future[Either[E, List[X]]]
  • 很简单

在这里,您可以使用Cats做到这一点:

// lines starting with `@` are ammonite imports of dependencies,
// add it to SBT if you don't use ammonite
@ import $ivy.`org.typelevel::cats-core:1.1.0`
@ import cats._, cats.data._, cats.implicits._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Either

// your input
val listFutureEither: List[Future[Either[String, Int]]] = Nil 

// monad transformer stack appropriate for the problem
type M[X] = EitherT[Future, String, X]

// converting input into monad-transformer-stack
val listM = listFutureEither.map(EitherT[Future, String, Int](_))

// solving your problem
val mList = Traverse[List].sequence[M, Int](listM)

// removing all traces of the monad-transformer-stack
val futureEitherList: Future[Either[String, List[Int]]] = mList.value

一个人可以争论这段代码是否“可读”,但好处是我不必发明任何东西:我实质上只是从经过全面测试的库中调用sequence方法,所以您不必甚至不必阅读它就可以看到该代码必须执行输入和输出类型所决定的“显而易见的事情”。