Last active
August 29, 2015 14:17
-
-
Save xuwei-k/a9a48b6c984674a43bb7 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.1" | |
scalaVersion := "2.11.6" |
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 scalaz.std.AllInstances._ | |
import either_and_future_sample.Main.{UserId, context} | |
import scalaz.Id.Id | |
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) | |
abstract class UsersRepository[F[_]](implicit val F: Monad[F]){ | |
import F.bindSyntax._ | |
import syntax.traverse._ | |
def followers(userId: UserId): F[List[User]] | |
// モナドで抽象化することにより、Fがモナドという条件さえあれば、 | |
// Fの具体的な型に関わらず、isFriendsメソッドは、全く同じものでよくなる | |
// これがモナドで抽象化するという本当の意味である? | |
def isFriends(user1: UserId, user2: UserId): F[Boolean] = | |
for{ | |
a <- followers(user1) | |
b <- followers(user2) | |
} yield a.exists(_.id == user2) && b.exists(_.id == user1) | |
// followerFollowerメソッドも同じように可能 | |
def followerFollower(userId: UserId): F[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 UsersRepository { | |
val id = | |
new UsersRepository[Id] { | |
def followers(userId: UserId): List[User] = { | |
// 実行時間計測のWriterのやつから使われる関係上、適当にダミーでsleep | |
Thread.sleep(util.Random.nextInt(1000)) | |
Nil | |
} | |
} | |
val either = | |
new UsersRepository[({type l[a] = Error \/ a})#l] { | |
def followers(userId: UserId): Error \/ List[User] = | |
\/.right(Nil) | |
} | |
val future = | |
new UsersRepository[Future] { | |
def followers(userId: UserId): Future[List[User]] = | |
Future.successful(Nil) | |
} | |
val eitherTFuture = | |
new UsersRepository[({type l[a] = EitherT[Future, Error, a]})#l] { | |
def followers(userId: UserId): EitherT[Future, Error, List[User]] = | |
F.point(Nil) | |
} | |
val writer = | |
new UsersRepository[({type l[a] = Writer[List[Long], a]})#l] { | |
def followers(userId: UserId): Writer[List[Long], List[User]] = { | |
val start = System.currentTimeMillis() | |
val result = id.followers(userId) | |
val time = System.currentTimeMillis() - start | |
Writer(List(time), result) | |
} | |
} | |
} | |
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 | |
def main(args: Array[String]): Unit = { | |
UsersRepository.id.isFriends(1, 2): Boolean | |
UsersRepository.either.isFriends(1, 2): Error \/ Boolean | |
UsersRepository.future.isFriends(1, 2): Future[Boolean] | |
UsersRepository.eitherTFuture.isFriends(1, 2): EitherT[Future, Error, Boolean] | |
val (times, result) = UsersRepository.writer.isFriends(1, 2).run | |
println("times " + times) | |
println(result) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment