Last active
November 25, 2018 01:52
-
-
Save x7c1/f54f3e30b6e57a958a0010feb55f1f0f to your computer and use it in GitHub Desktop.
examples without EitherT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // https://xuwei-k.hatenablog.com/entry/20140920/1411236567 | |
| import scala.concurrent.{ExecutionContext, Future} | |
| trait UserId | |
| sealed trait Error | |
| final case class UserNotFound(userId: UserId) extends Error | |
| final case class ConnectionError(message: String) extends Error | |
| final case class User(id: UserId, name: String) | |
| object UsersRepository { | |
| def followers(userId: UserId): Future[Either[Error, List[User]]] = ??? | |
| } | |
| class Example1(implicit ec: ExecutionContext) { | |
| import UsersRepository.followers | |
| def isFriends(user1: UserId, user2: UserId): Future[Either[Error, Boolean]] = { | |
| followers(user1).flatMap { | |
| case Right(a) => | |
| followers(user2).map { | |
| case Right(b) => | |
| Right(a.exists(_.id == user2) && b.exists(_.id == user1)) | |
| case Left(e) => | |
| Left(e) | |
| } | |
| case Left(e) => | |
| Future.successful(Left(e)) | |
| } | |
| } | |
| } | |
| class Example2(implicit ec: ExecutionContext) { | |
| import UsersRepository.followers | |
| private type F[L, R] = Future[Either[L, R]] | |
| def map2[L, R1, R2, R3]( | |
| a1: => F[L, R1], | |
| a2: => F[L, R2])(f: (R1, R2) => R3): F[L, R3] = { | |
| a1 flatMap { | |
| case Right(value) => a2.map(_.map(f(value, _))) | |
| case Left(error) => Future successful Left(error) | |
| } | |
| } | |
| def isFollower(u1: UserId, u2: UserId): Future[Either[Error, Boolean]] = { | |
| followers(u1).map(_.map(_.exists(_.id == u2))) | |
| } | |
| def isFriends(user1: UserId, user2: UserId): Future[Either[Error, Boolean]] = { | |
| map2( | |
| isFollower(user2, user1), | |
| isFollower(user1, user2), | |
| )(_ && _) | |
| } | |
| } | |
| class Example3(implicit ec: ExecutionContext) { | |
| import UsersRepository.followers | |
| def isFriends(user1: UserId, user2: UserId): Future[Either[Error, Boolean]] = { | |
| followers(user1).flatMap { | |
| case Right(a) if a.exists(_.id == user2) => | |
| followers(user2).map(_.map(_.exists(_.id == user1))) | |
| case Right(_) => | |
| Future successful Right(false) | |
| case Left(e) => | |
| Future successful Left(e) | |
| } | |
| } | |
| } | |
| class Example4(implicit ec: ExecutionContext) { | |
| import UsersRepository.followers | |
| def followerFollower(userId: UserId): Future[Either[Error, List[User]]] = { | |
| followers(userId).flatMap { | |
| case Right(a) => | |
| val ids = a.map(_.id) | |
| Future.traverse(ids)(followers).map { c => | |
| c.foldLeft(Right(Nil): Either[Error, List[User]]) { | |
| case (Right(d), Right(e)) => | |
| Right(d ::: e) | |
| case (e @ Left(_), _) => | |
| e | |
| case (_, e @ Left(_)) => | |
| e | |
| } | |
| .right | |
| .map { | |
| _.filterNot(user => ids.contains(user.id) || userId == user.id) | |
| } | |
| } | |
| case Left(e) => | |
| Future.successful(Left(e)) | |
| } | |
| } | |
| } | |
| class Example5(implicit ec: ExecutionContext) { | |
| import UsersRepository.followers | |
| case class LoadedUsers(errors: List[Error] = Nil, users: List[User] = Nil) { | |
| def discard(ids: List[UserId]): LoadedUsers = copy( | |
| users = users.filterNot(ids contains _.id) | |
| ) | |
| def add(loaded: Either[Error, List[User]]): LoadedUsers = loaded match { | |
| case Left(error) => | |
| copy(errors = errors :+ error) | |
| case Right(xs) => | |
| copy(users = users ::: xs) | |
| } | |
| } | |
| def followerFollower(userId: UserId): Future[LoadedUsers] = { | |
| def retrieve(ids: List[UserId]): Future[LoadedUsers] = { | |
| Future | |
| .traverse(ids)(followers) | |
| .map(_.foldLeft(LoadedUsers()) { _ add _ }) | |
| .map(_ discard userId :: ids) | |
| } | |
| followers(userId).flatMap { | |
| case Right(users) => retrieve(users.map(_.id)) | |
| case Left(error) => Future successful LoadedUsers(List(error)) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment