Using different monads to understand

Can I use different monads for understanding? Here is the code that usesmap

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")
  }
}

The simple version for understanding does not work for obvious reasons, but is it possible to make it work with some additional code? I know this is possible in C #, so it would be weird if it weren’t in Scala.

+4
source share
2 answers

You can use only one type of monad in for understanding, since it is just syntactic sugar for flatMapand map.

If you have a monad stack (e.g. Future[Option[A]]), you can use a monad transformer, but this is not applicable here.

: Option Try Option Try 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].

sealed trait Error extends Exception
case class PostNotFound(userId: Int) extends Error
case object NotAuthorized extends Error 
+1

, , [Try [Post]]

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")
}

a .

fors:

  for {
    post <- find(id)
  } yield {
    for {
      tryOfPost <- permitted(post, userId)
    } yield {
      tryOfPost.copy(text = text)
    }
  }

Try. , ​​Try None . , , , .

  for {
    post <- find(id).fold[Try[Post]](Failure[Post](new OtherException))(Success(_))
    permittedPost <- permitted(post, userId)
  } yield {
    permittedPost.copy(text = text)
  }

OptionT scalaz, , OptionTTry.

, , , .

+3

Source: https://habr.com/ru/post/1613556/


All Articles