Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@xuwei-k
Last active August 29, 2015 14:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xuwei-k/a9a48b6c984674a43bb7 to your computer and use it in GitHub Desktop.
Save xuwei-k/a9a48b6c984674a43bb7 to your computer and use it in GitHub Desktop.
libraryDependencies += "org.scalaz" %% "scalaz-core" % "7.1.1"
scalaVersion := "2.11.6"
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