Skip to content

Instantly share code, notes, and snippets.

@rirakkumya
Created April 14, 2012 05:55
Show Gist options
  • Star 44 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rirakkumya/2382341 to your computer and use it in GitHub Desktop.
Save rirakkumya/2382341 to your computer and use it in GitHub Desktop.
def index(id:String) = Action {
getFirstData(id)
}
private def getFirstData(id:String) = {
Cache.get(id) match {
case Some(id2) => getSecondData(id2)
case None => NotFound
}
}
private def getSecondData(id2:String) = {
Cache.get(id2) match {
case Some(result) => Ok(result)
case None => NotFound
}
}
def index(id:String) = Action {
Cache.get(id) match {
case Some(id2) => {
Cache.get(id2) match {
case Some(result) => Ok(result)
case None => NotFound
}
}
case None => NotFound
}
}
@tototoshi
Copy link

一点だけ気になったので

    case Some(r) if r.head == 'x' => Right("foo")

これは r == "" のときにNoSuchElementExceptionが飛ぶので、

    case Some(r) if r.startsWith("x") => Right("foo")

にするべきでしょう。

@rirakkumya
Copy link
Author

確かに。ツッコミありがとうございます。

@rirakkumya
Copy link
Author

Action拡張すれば使い易くなりそう。 Right => Continue Left => Break でAlias切るか。 名前がイマイチだけど。良いネーミング無いかな。

@rirakkumya
Copy link
Author

forもscalazも使わずにシンプルに書けた
playで使うならこれが一番良さそう

case class Bind[a1,a2](x:Either[a1,a2]) {
  def >>=[b](f:a2 => Either[a1,b]):Either[a1,b] = x.right flatMap f
}

implicit def either2Bind[a](s:Either[Result,a]) = Bind(s)

def index(id:String) = Action {
  Right(id) >>= firstData >>= secondData >>= result merge
}

private def firstData(id:String) = {
  Cache.get(id) match {
    case Some(r) if r.startsWith("x") => Right("foo")
    case Some(r) => Right(r)
    case None => Left(NotFound)
  }
}
private def secondData(id:String) = {
  Cache.get(id) match {
    case Some(r) if r == "badcode" => Left(BadRequest)
    case Some(r) => Right(r)
    case None => Left(NotFound)
  }
}
private def result(id:String) = Right(Ok(id))

@rirakkumya
Copy link
Author

これでもいいけど、上の書き方の方が保守しやすいな

case class Bind[a1,a2](x:Either[a1,a2]) {
  def >>=[b](f:a2 => Either[a1,b]):Either[a1,b] = x.right flatMap f
}

implicit def either2Bind[a](s:Either[Result,a]) = Bind(s)

def index(id:String) = Action {
  Right(id) >>= { id => 
    Cache.get(id) match {
      case Some(r) if r.startsWith("x") => Right("foo")
      case Some(r) => Right(r)
      case None => Left(NotFound)
    }
  } >>= { id => 
    Cache.get(id) match {
      case Some(r) if r == "badcode" => Left(BadRequest)
      case Some(r) => Right(r)
      case None => Left(NotFound)
    }
  } >>= { r => Right(Ok(r)) } merge
}

@xuwei-k
Copy link

xuwei-k commented Jun 6, 2013

https://github.com/scalaz/scalaz/blob/v7.0.0/core/src/main/scala/scalaz/Kleisli.scala#L15

Kleisli の合成だった

trait Response
case object BadRequest extends Response
case object NotFound extends Response
case class Ok(message: String) extends Response

object Cache{ def get(id: String): Option[String] = ??? }

import scalaz._,Scalaz._

val getOrNotFound = Kleisli[({type λ[+α]=Either[Response, α]})#λ, String, String]{
  id => Cache.get(id) toRight NotFound
}

val getOrBad = Kleisli[({type λ[+α]=Either[Response, α]})#λ, String, String]{
  id => Cache.get(id) toRight BadRequest
}

def index(id: String) = (getOrNotFound >=> getOrBad >=> getOrNotFound) run id map Ok merge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment