使用哪个 Monad Transformer?
Which Monad Transformer to use?
我正在尝试编写下面的验证函数,以便在遇到第一个错误后停止验证。 three
的 return 类型与其他函数不同。我应该使用哪个 monad 转换器来编译此代码?
import scalaz._
import Scalaz._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def one(a : String): Disjunction[Int, String] =
a == "one" match {
case true => \/-("one")
case false => -\/(2)
}
def two(a : String): Disjunction[Int, String] =
a == "two" match {
case true => \/-("two")
case false => -\/(3)
}
def three(a : String): Future[Disjunction[Int, String]] =
Future (a == "three") map {
case true => \/-("three")
case false => -\/(4)
}
def validate(a : String) = for {
e1 <- one(a)
e2 <- two(a)
e3 <- EitherT(three(a))
} yield (e1 |+| e2 |+| e3)
编译错误:
Error:(27, 7) type mismatch;
found : scalaz.EitherT[scala.concurrent.Future,Int,String]
required: scalaz.\/[?,?]
e3 <- EitherT(three(a))
^
Error:(66, 7) type mismatch;
found : scalaz.EitherT[scala.concurrent.Future,Int,String]
required: scalaz.\/[?,?]
e3 <- EitherT(three(a))
^
在这种情况下,您可以采用两种通用方法。第一个是让你所有的方法 return 成为你知道你将要使用的堆栈(在本例中 EitherT[Future, Int, ?]
),或者你可以让每个单独的方法 return 成为最常用的类型准确地捕捉它自己的效果,然后在合成它们时适当地提高你得到的值。
如果您确切知道用法将是什么样子,第一种方法可以使用法在语法上更方便,但后一种方法更灵活,在我看来通常是更好的选择。在您的情况下,它看起来像这样:
import scalaz._, Scalaz._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def one(a: String): Disjunction[Int, String] = (a == "one").either("one").or(2)
def two(a: String): Disjunction[Int, String] = (a == "two").either("two").or(3)
def three(a: String): EitherT[Future, Int, String] = EitherT(
Future(a == "three").map(_.either("three").or(4))
)
def validate(a: String) = for {
e1 <- EitherT.fromDisjunction[Future](one(a))
e2 <- EitherT.fromDisjunction[Future](two(a))
e3 <- three(a)
} yield (e1 |+| e2 |+| e3)
然后:
scala> validate("one").run.foreach(println)
-\/(3)
scala> validate("x").run.foreach(println)
-\/(2)
如果出于某种原因你有一个普通的旧 Future
,你想在 for
-comprehension 中使用,你可以将它提升到 EitherT[Future, String, A]
和 .liftM[EitherT[?[_], String, ?]]
.
(请注意,此方法可能不是很有用,因为它永远不会成功(字符串不能等于 "one"
、"two"
和 "three"
同时),但至少构图是可行的。)
关于如何更普遍地选择 monad 转换器堆栈:您只需将类型翻转过来,这样 Future[Disjunction[Int, ?]]
就变成了 EitherT[Future, Int, ?]
,等等。在这种情况下,具体来说,Future
没有 monad 转换器(它不可遍历,并且不可能在不阻塞的情况下实现 FutureT
),所以你知道它必须在内部进行,无论如何。
Travis 的回答没有什么可补充的(像往常一样),但如果您在 Play 中使用它!申请,也许https://github.com/Kanaka-io/play-monadic-actions可以提供一些帮助。
我正在尝试编写下面的验证函数,以便在遇到第一个错误后停止验证。 three
的 return 类型与其他函数不同。我应该使用哪个 monad 转换器来编译此代码?
import scalaz._
import Scalaz._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def one(a : String): Disjunction[Int, String] =
a == "one" match {
case true => \/-("one")
case false => -\/(2)
}
def two(a : String): Disjunction[Int, String] =
a == "two" match {
case true => \/-("two")
case false => -\/(3)
}
def three(a : String): Future[Disjunction[Int, String]] =
Future (a == "three") map {
case true => \/-("three")
case false => -\/(4)
}
def validate(a : String) = for {
e1 <- one(a)
e2 <- two(a)
e3 <- EitherT(three(a))
} yield (e1 |+| e2 |+| e3)
编译错误:
Error:(27, 7) type mismatch;
found : scalaz.EitherT[scala.concurrent.Future,Int,String]
required: scalaz.\/[?,?]
e3 <- EitherT(three(a))
^
Error:(66, 7) type mismatch;
found : scalaz.EitherT[scala.concurrent.Future,Int,String]
required: scalaz.\/[?,?]
e3 <- EitherT(three(a))
^
在这种情况下,您可以采用两种通用方法。第一个是让你所有的方法 return 成为你知道你将要使用的堆栈(在本例中 EitherT[Future, Int, ?]
),或者你可以让每个单独的方法 return 成为最常用的类型准确地捕捉它自己的效果,然后在合成它们时适当地提高你得到的值。
如果您确切知道用法将是什么样子,第一种方法可以使用法在语法上更方便,但后一种方法更灵活,在我看来通常是更好的选择。在您的情况下,它看起来像这样:
import scalaz._, Scalaz._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def one(a: String): Disjunction[Int, String] = (a == "one").either("one").or(2)
def two(a: String): Disjunction[Int, String] = (a == "two").either("two").or(3)
def three(a: String): EitherT[Future, Int, String] = EitherT(
Future(a == "three").map(_.either("three").or(4))
)
def validate(a: String) = for {
e1 <- EitherT.fromDisjunction[Future](one(a))
e2 <- EitherT.fromDisjunction[Future](two(a))
e3 <- three(a)
} yield (e1 |+| e2 |+| e3)
然后:
scala> validate("one").run.foreach(println)
-\/(3)
scala> validate("x").run.foreach(println)
-\/(2)
如果出于某种原因你有一个普通的旧 Future
,你想在 for
-comprehension 中使用,你可以将它提升到 EitherT[Future, String, A]
和 .liftM[EitherT[?[_], String, ?]]
.
(请注意,此方法可能不是很有用,因为它永远不会成功(字符串不能等于 "one"
、"two"
和 "three"
同时),但至少构图是可行的。)
关于如何更普遍地选择 monad 转换器堆栈:您只需将类型翻转过来,这样 Future[Disjunction[Int, ?]]
就变成了 EitherT[Future, Int, ?]
,等等。在这种情况下,具体来说,Future
没有 monad 转换器(它不可遍历,并且不可能在不阻塞的情况下实现 FutureT
),所以你知道它必须在内部进行,无论如何。
Travis 的回答没有什么可补充的(像往常一样),但如果您在 Play 中使用它!申请,也许https://github.com/Kanaka-io/play-monadic-actions可以提供一些帮助。