Scala ActionBuilder接受IO[Result],而不是未来的[Result]

Scala ActionBuilder接受IO[Result],而不是未来的[Result],scala,scalaz,playframework-2.3,Scala,Scalaz,Playframework 2.3,我编写了一个小示例,在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 { reque

我编写了一个小示例,在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)) }
    }
  }
}
但是,我想知道使用play ActionBuilder是否会导致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行为相同的解决方法吗(即可选的请求参数和正文解析器)?

如果重新定义
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]
您可以制作一个trait扩展
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]
 }
这与我们最初定义的几乎完全相同,但不是那么直接


兴趣在于
编写动作,而不是提供基本动作。

您确定使用play-2.0,而不是play-2.2或play-2.3吗?我使用的是play 2.3.7。如果您也想访问请求参数,则第一种解决方案不起作用,第二种解决方案也不起作用,因为要将IOAction与ActionBuilder结合使用,IOAction的
io
参数应该是
Action[A]
类型。见: