Created
September 20, 2014 18:06
-
-
Save xuwei-k/051c3b00129b7a0dfcd6 to your computer and use it in GitHub Desktop.
This file contains 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
libraryDependencies += "org.scalaz" %% "scalaz-core" % "7.1.0" | |
//libraryDependencies += "org.typelevel" %% "scalaz-contrib-210" % "0.1.5" // for scalaz 7.0.x | |
scalaVersion := "2.10.4" |
This file contains 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
package either_and_future_sample | |
import scalaz._ | |
import scala.concurrent.{ExecutionContext, Future} | |
import syntax.traverse._ | |
import std.list._ | |
import std.either._ | |
import scalaz.std.scalaFuture._ // for scalaz 7.1.0 | |
// import scalaz.contrib.std.scalaFuture._ // for scalaz 7.0.x | |
import either_and_future_sample.Main.{UserId, context} | |
sealed trait Error | |
/** 引数であたえられたUserIdのUserが、そもそも存在しなかった場合 */ | |
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]]] = ??? | |
def followersNoFuture(userId: UserId): Error \/ List[User] = ??? | |
// Futureでないversion | |
def followerFollower0(userId: UserId): Error \/ List[User] = | |
for{ | |
a <- followersNoFuture(userId) | |
b = a.map(_.id) | |
c <- b.traverseU(followersNoFuture) | |
} yield c.flatten.distinct.filterNot(user => b.contains(user.id) || user.id == userId) | |
// Futureになったもの。Scalazもできるだけ使わないで書くとすると、foldLeftなどしないといけなくて辛い | |
def followerFollower1(userId: UserId): Future[Either[Error, List[User]]] = { | |
followers(userId).flatMap{ | |
case Right(a) => | |
val b = a.map(_.id) | |
Future.traverse(b)(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 => b.contains(user.id) || userId == user.id)} | |
} | |
case Left(e) => | |
Future.successful(Left(e)) | |
} | |
} | |
// scalaz.Traverseなども使って書いたもの。traverseやsequence関数大量でこれも少し辛い。 | |
// そもそもテストしてないから合ってるのか自信ない。 | |
// もうちょっと綺麗に書けるというか、書き方かなり色々ある気がする。 | |
def followerFollower2(userId: UserId): Future[Either[Error, List[User]]] = { | |
followers(userId).flatMap{ | |
case Right(a) => | |
val b = a.map(_.id) | |
Future.traverse(b)(followers).map{ x => | |
x.traverse(_.sequenceU).flatten.sequenceU.map( | |
_.filterNot(user => b.contains(user.id) || userId == user.id) | |
) | |
} | |
case Left(e) => | |
Future.successful(Left(e)) | |
} | |
} | |
} | |
object UsersRepositoryScalaz { | |
def followers(userId: UserId): EitherT[Future, Error, List[User]] = ??? | |
// なんということでしょう! | |
// この場合も、scalaz.EitherTを使えば、Futureなしversionと同じコードでいけますね? | |
def followerFollower(userId: UserId): EitherT[Future, Error, List[User]] = | |
for{ | |
a <- followers(userId) | |
b = a.map(_.id) | |
c <- b.traverseU(followers) | |
} yield c.flatten.distinct.filterNot(user => b.contains(user.id) || user.id == userId) | |
} | |
object Main { | |
// ダミーの、単一スレッドでだけ使うExecutionContext | |
implicit val context: ExecutionContext = new ExecutionContext { | |
override def execute(runnable: Runnable): Unit = runnable.run() | |
override def reportFailure(t: Throwable): Unit = t.printStackTrace() | |
} | |
type UserId = Long | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment