Skip to content

Instantly share code, notes, and snippets.

@rirakkumya
Created May 7, 2012 05:54
Show Gist options
  • Save rirakkumya/2626167 to your computer and use it in GitHub Desktop.
Save rirakkumya/2626167 to your computer and use it in GitHub Desktop.
play2 monadic + DSL programming
package controllers
import play.api._
import play.api.mvc._
import play.api.cache._
import play.api.Play.current
object Application extends Controller {
import EA._
def index(id:String) = EitherAction {req =>
id >>= {
Cache.getAs[String](_) match {
case Some(r) if r.startsWith("x") => "foo" 継続
case Some(r) => r 継続
case None => BadRequest 終了
}
} >>= {
Cache.getAs[String](_) match {
case Some(r) if r == "badcode" => BadRequest ×
case Some(r) => r ○
case None => NotFound ×
}
} >>= {x => Ok(x) 正常}
}
}
package controllers
import play.api.mvc._
object EA {
class Bind[a1,a2](x:Either[a1,a2]) {
def >>=[b](f:a2 => Either[a1,b]):Either[a1,b] = x.right flatMap f
def >>==[b](f:a2 => Either[a1,b]):Either[a1,b] = {
val result = x.right flatMap f
println("input[%s] output[%s]".format(x,result))
result
}
}
implicit def either2Bind[a](s:Either[Result,a]) = new Bind(s)
implicit def any2Bind[a](x:a) = new Bind[Result,a](Right(x))
class AnyToEither[a](x:a) {
val success = Right(x)
val continue = Right(x)
val 継続 = Right(x)
val 正常 = Right(x)
val ○ = Right(x)
val fail = Left(x)
val end = Left(x)
val 終了 = Left(x)
val 異常 = Left(x)
val × = Left(x)
}
implicit def any2Either[a](x:a) = new AnyToEither(x)
def EitherAction(
f:Request[AnyContent] => Either[Result,Result]
):Action[AnyContent] = Action{f(_) merge}
}
GET /:id controllers.Application.index(id)
GET /assets/*file controllers.Assets.at(path="/public", file)
@rirakkumya
Copy link
Author

Cache等のOptionが帰ってくる関数を連鎖して呼び出すと、どんどん入れ子になって、訳がわからないよ…になる問題を解決する方法。

関数の連鎖は">>="を記述する。
">>=="と記述した場合、debugモードとなり標準出力に入力と出力の値が表示される。

戻り値に

  • success
  • continue
  • 継続
  • 正常

を記述すると、処理を継続し

  • fail
  • end
  • 終了
  • 異常
  • ×

を記述すると終了する。
組み合わせは自由。
継続する場合は任意の型、終了する場合はResult型を返す。

複雑な多重入れ子の記述例

Action

  def index(id:String) = Action {
    Cache.getAs[String](id) match {
      case Some(r1) => Cache.getAs[String](r1) match {
        case Some(r2) if r2 == "finished" => Ok(r2)
        case Some(r2) => Cache.getAs[String](r2) match {
          case Some(r3) => Ok(r3)
          case None => NotFound
        }
        case None => BadRequest
      }
      case None => BadRequest
    }
  }

EitherAction

  def index(id:String) = EitherAction {req =>
    id >>= {
      Cache.getAs[String](_) match {
        case Some(r) => r         継続
        case None => BadRequest  異常
      }
    } >>= {
      Cache.getAs[String](_) match {
        case Some(r) if r == "finished" => Ok(r) 終了
        case Some(r) => r                         継続
        case None => BadRequest                  異常
      }
    } >>= {
      Cache.getAs[String](_) match {
        case Some(r) => Ok(r)  正常
        case None => NotFound  終了
      }
    }
  }

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