Created
March 5, 2015 15:28
-
-
Save takei-shg/b7b67e1cc52126c08049 to your computer and use it in GitHub Desktop.
com.twitter.util.Future Chain with OptionT
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
import scalaz._ | |
import Scalaz._ | |
import scalaz.OptionT._ | |
import com.twitter.util.Future | |
/** | |
* Simple example of Future chain, which only shows type level consistency. | |
* Future chain can be implemented with optionT or simple flatMap chain. | |
*/ | |
object Main extends App { | |
object JSONParser { | |
def read(request: Request): Option[AdRequest] = ??? | |
} | |
object LocalCache { | |
def load(): Future[CampaignContext] = ??? | |
} | |
object CampaignFilter { | |
def filter(request: AdRequest, ctx: CampaignContext): Option[AdResponse] = ??? | |
} | |
object RedisService { | |
def getKey(): Future[Option[SessionKey]] = ??? | |
} | |
/** | |
* To use optionT, necessary to make com.twitter.util.Future as instance of Monad | |
*/ | |
object FutureInstances { | |
implicit val monadInstance = new Functor[Future] with Monad[Future] { | |
def point[A](a: => A): Future[A] = Future.value(a) | |
def bind[A, B](fa: Future[A])(f: A => Future[B]): Future[B] = fa.flatMap(f) | |
override def map[A, B](fa: Future[A])(f: A => B): Future[B] = fa.map(f) | |
} | |
} | |
import FutureInstances._ | |
object AdService { | |
val NO_CONTENT = "" | |
def apply(request: Request): Future[Response] = { | |
(for { | |
adReq <- optionT(JSONParser.read(request).point[Future]) | |
ctx <- LocalCache.load().liftM[OptionT] | |
adRes <- optionT(CampaignFilter.filter(adReq, ctx).point[Future]) | |
sessionKey <- optionT(RedisService.getKey()) | |
} yield mkResponse(adRes, sessionKey)).run.map { | |
_.getOrElse(Response(NO_CONTENT)) | |
} | |
} | |
/* | |
def apply(request: Request): Future[Response] = { | |
val adReqOpt: Option[AdRequest] = JSONParser.read(request) | |
val fAdResOpt: Future[Option[AdResponse]] = adReqOpt.map { adReq => | |
val fCtx: Future[CampaignContext] = LocalCache.load() | |
fCtx.map { ctx => | |
CampaignFilter.filter(adReq, ctx) | |
} | |
}.getOrElse { | |
Future.value(None) | |
} | |
fAdResOpt.flatMap { adResOpt => | |
adResOpt.map { adRes => | |
val fSessionKeyOpt = RedisService.getKey() | |
fSessionKeyOpt.flatMap { sessionKeyOpt => | |
sessionKeyOpt.map { sessionKey => | |
Future.value(mkResponse(adRes, sessionKey)) | |
}.getOrElse { | |
Future.value(Response(NO_CONTENT)) | |
} | |
} | |
}.getOrElse { | |
Future.value(Response(NO_CONTENT)) | |
} | |
} | |
} | |
*/ | |
def mkResponse(adRes: AdResponse, sessionKey: SessionKey): Response = Response(???) | |
} | |
type Request = Int | |
case class Response(body: String) | |
type AdRequest = Int | |
type AdResponse = Int | |
type CampaignContext = Int | |
type SessionKey = Int | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment