我知道Monad
可以在Scala中表达如下:
trait Monad[F[_]] {
def flatMap[A, B](f: A => F[B]): F[A] => F[B]
}
Run Code Online (Sandbox Code Playgroud)
我明白为什么它有用.例如,给定两个功能:
getUserById(userId: Int): Option[User] = ...
getPhone(user: User): Option[Phone] = ...
Run Code Online (Sandbox Code Playgroud)
我可以轻松编写函数,getPhoneByUserId(userId: Int)
因为它Option
是一个monad:
def getPhoneByUserId(userId: Int): Option[Phone] =
getUserById(userId).flatMap(user => getPhone(user))
Run Code Online (Sandbox Code Playgroud)
...
现在我Applicative Functor
在Scala中看到:
trait Applicative[F[_]] {
def apply[A, B](f: F[A => B]): F[A] => F[B]
}
Run Code Online (Sandbox Code Playgroud)
我想知道何时应该使用它而不是 monad.我猜选项和列表都是Applicatives
.你能给出使用apply
Option和List的简单例子,并解释为什么我应该使用它而不是 flatMap
?
我想Future[(Class1,Class2,Class3)]
从下面的代码创建一个类型的Future .然而,我发现这样做的唯一方法是使用zip().我发现解决方案很难看,并且不是最佳的.任何人都可以开悟我.
val v = for (
a <- {
val f0:Future[Class1] = process1
val f1:Future[Class2] = process2
val f2:Future[Class3] = process3
f0.zip(f1).zip(f2).map(x => (x._1._1,x._1._2,x._2))
} yield a // Future[(Class1,Class2,Class3)]
Run Code Online (Sandbox Code Playgroud)
我也曾尝试使用Future.sequence(List(f0, f1, f2))
,但是这不会为新的未来的工作会有的类型Future[List[U]]
,其中U
是的LUB Class1/2/3
,而我希望有一个3元组保留原始类型
假设我需要运行两个并发计算,等待它们,然后组合它们的结果.更具体地说,我需要运行f1: X1 => Y1
并f2: X2 => Y2
同时然后调用f: (Y1, Y2) => Y
最终得到一个值Y
.
我可以创建未来的计算 fut1: X1 => Future[Y1]
,fut2: X2 => Future[Y2]
然后组合它们以fut: (X1, X2) => Future[Y]
使用monadic组合.
问题是monadic组合意味着顺序等待.在我们的例子中,它意味着我们先等待一个未来,然后我们将等待另一个未来.例如.如果它需要2秒.到第一个未来完成,只需1秒.到第二个未来失败,我们浪费1秒.
因此,它看起来像我们所需要的应用性期货的组成等到要么两者完全或至少一个未来的失败.是否有意义 ?你会如何实施<*>
期货?