在理解中使用不同的单子 [英] Using different monads in for-comprehension
问题描述
可以在理解中使用不同的单子吗?这是使用map
Can different monads be used in for-comprehensions? Here's the code that uses map
case class Post(id: Int, text: String)
object PostOps {
def find(id: Int) : Option[Post] = if (id == 1) Some(Post(1, "text")) else None
def permitted(post: Post, userId: Int) : Try[Post] = if (userId == 1) Success(post) else Failure(new UnsupportedOperationException)
def edit(id: Int, userId : Int, text: String) = find(id).map(permitted(_, userId).map(_.copy(text = text))) match {
case None => println("Not found")
case Some(Success(p)) => println("Success")
case Some(Failure(_)) => println("Not authorized")
}
}
直接理解的版本由于明显的原因而无法正常工作,但是是否可以使它与其他一些代码一起工作?我知道在C#中是可能的,所以如果不在Scala中,那会很奇怪.
The straightforward version of for-comprehension doesn't work for obvious reasons, but is it possible to make it work with some additional code? I know it's possible in C# so it would be weird if it is not in Scala.
推荐答案
您只能在a中使用一种monad进行理解,因为它只是flatMap
和map
的语法糖.
You can only use one type of monad in a for comprehension, since it is just syntactic sugar for flatMap
and map
.
如果您有一堆monad(例如Future[Option[A]]
),则可以使用monad变压器,但这不适用于此.
If you have a stack of monads (eg Future[Option[A]]
) you could use a monad transformer, but that does not apply here.
针对您的情况的解决方案可能是使用一个monad:从Option
转到Try
或从Option
和Try
转到Either[String, A]
.
A solution for your case could be to use one monad : go from Option
to Try
or go from both Option
and Try
to Either[String, A]
.
def tryToEither[L, R](t: Try[R])(left: Throwable => L): Either[L, R] =
t.transform(r => Success(Right(r)), th => Success(Left(left(th)))).get
def edit(id: Int, userId: Int, text: String) = {
val updatedPost = for {
p1 <- find(id).toRight("Not found").right
p2 <- tryToEither(permitted(p1, userId))(_ => "Not Authorized").right
} yield p2.copy(text = text)
updatedPost match {
case Left(msg) => println(msg)
case Right(_) => println("success")
}
}
您可以定义错误类型而不是使用String
,这样您就可以使用Either[Error, A]
.
You could define an error type instead of using String
, this way you can use Either[Error, A]
.
sealed trait Error extends Exception
case class PostNotFound(userId: Int) extends Error
case object NotAuthorized extends Error
这篇关于在理解中使用不同的单子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!