我写了一个小例子,在play框架中使用scalaz的IO monad。以下示例按预期工作:
object IOAction {
def apply(action:IO[Result]):Result = action.unsafePerformIO
}
class ExampleController extends Controller {
val now:IO[DateTime] = IO { DateTime.now }
def index = Action { request =>
IOAction {
now.map { dateTime => Ok(views.html.index(dateTime)) }
}
}
}
但是,我想知道使用PlayBuilder是否会导致一个稍微冗长的API。理想情况下,我想写:
class ExampleController extends Controller {
val now:IO[DateTime] = IO { DateTime.now }
def index = IOAction { request =>
now.map { dateTime => Ok(views.html.index(dateTime)) }
}
}
我卡住了,因为invokeBlock
函数似乎已修复为Future[Result]
类型。
def invokeBlock[A](request: R[A], block: P[A] => Future[Result]): Future[Result]
有没有人知道IOAction行为与Action相同的解决方法(即可选的请求参数和正文解析器)?
答案 0 :(得分:2)
如果您重新定义IOAction
,那么后一个示例是否有效:
object IOAction {
def apply(io: Request[AnyContent] => IO[Result]): Action[AnyContent] =
Action { (request: Request[AnyContent]) => io(request).unsafePerformIO }
}
在Controller
对象中你可以做
def foo(): Handler = IOAction { request =>
Ok("foo").point[IO]
}
即。 Future
是异步(IO)计算,其中IO
是同步的。从IO
到Future
的转换很容易。
IO
和ActionBuilder
的组合并不适合锻炼。
ActionBuilder
并未考虑IO
。它有
final def apply(block: ⇒ Result): Action[AnyContent]
final def apply(block: (R[AnyContent]) ⇒ Result): Action[AnyContent]
final def async(block: ⇒ Future[Result]): Action[AnyContent]
final def async(block: R[AnyContent]) ⇒ Future[Result]): Action[AnyContent]
你可以制作一个延伸ActionBuilder[R]
的特征并提供,比如说:
final def io(block: => Result): Action[AnyContent]
final def io(block R[AnyContent] => Result): Action[AnyContent]
然后你可以定义:
object IOAction extends IOActionBuilder[Request] { /* ... */ }
并将其用作:
def foo = IOAction.io { request =>
Ok("foo").point[IO]
}
这与我们首先定义的几乎完全相同,但不是那么直接。
在ActionComposition.scala感兴趣的是 撰写动作,不提供基本动作。