fork download
  1. object Main extends App {
  2. val db = ""
  3. def handleTransfer(req: TransferRequest): Either[Err, Result] = {
  4. val resultNested = for {
  5. u1 <- req.user1.lookup(db).nestError
  6. u2 <- req.user2.lookup(db).earlyResult { e =>
  7. Result(s"Cannot find ${req.user2}: $e")
  8. }
  9. depositor <- u2.checkAccess(u1).earlyResult { _ =>
  10. Result(s"$u2 has not given you deposit access")
  11. }
  12. withdrawal <- u1.withdraw(req.amount).nestError
  13. conf <- depositor.accept(withdrawal).nestError
  14. } yield {
  15. Result(s"You transferred $withdrawal to $u2, confirmation number $conf")
  16. }
  17. resultNested.joinLeft
  18. }
  19.  
  20. implicit class LeftNestingEither[A, B](either: Either[A, B]) {
  21. def nestError: Either[Either[A, Nothing], B] =
  22. either.left.map(Left(_))
  23.  
  24. def earlyResult[C](errorToResult: A => C): Either[Either[Nothing, C], B] =
  25. either.left.map(a => Right(errorToResult(a)))
  26. }
  27. }
  28.  
  29. case class Err(msg: String)
  30. case class Result(msg: String)
  31. class User() {
  32. def checkAccess(that: User): Either[Err, User] = ???
  33. def withdraw(amount: Double): Either[Err, Double] = ???
  34. def accept(amount: Double): Either[Err, Int] = ???
  35. }
  36. class UserName() {
  37. def lookup(db: Any): Either[Err, User] = ???
  38. }
  39. case class TransferRequest(user1: UserName, user2: UserName, amount: Double)
  40.  
Success #stdin #stdout 0.28s 2181632KB
stdin
Standard input is empty
stdout
Standard output is empty