2

我已经在 scala 中实现了以下 monad,它使用用于请求的 URL 和参数包装了调度结果

import org.json4s._
import scala.concurrent.{ExecutionContext, Future}

case class Result[T](url:String,params:JValue,result:Future[T]) {
  self =>
  def flatMap[S](f: T => Result[S])(implicit executionContext:ExecutionContext):Result[S] = {
    val result_ = f andThen (_.result)
    Result(self.url,self.params,this.result flatMap result_)
  }

  def map[B](f: T => B)(implicit executionContext:ExecutionContext):Result[B] =
    Result(this.url,this.params,this.result map f )

}

我遇到的问题在于flatmap. 为了flatmap正确,urlandparams需要来自f,即f: T => Result[S]。在上面的示例中,虽然它编译得很好并且签名正是我所需要的,但self.urlandself.params意味着urland永远不会被正在编辑params的 that 更新,换句话说,我不知道如何获取and变量从何时被调用的应用程序。ResultflatMapurlparamfflatMap

尽管T是必需的,但andRequest[S]却不是必需的,那么从 the中分离出来的 scala 方法是什么,以便我可以正确定义?urlparamsurl,paramsresultflatMap

注意:monad 背后的一般目的是让我可以处理HTTP调度的结果(即Future[T]),同时能够携带urlparams用于请求,flatMaps更新url,paramsresult(它是一个新请求),其中映射只是修改result

编辑:这是我当前如何使用 monad 的示例

  val restResponse = for {
    token <- Authenticate.Helpers.mainLogin // Type Result[String]
    userSessionToken <- Authenticate.Helpers.loginToken("someUser","somePassword",token) // Type Result[String]
    someOtherCommand <- DataService.getInitialData(token,userSessionToken) map
        (_ \ "someData" \ "someMoreData" \\ "evenMoreData" match {
          case JString(s) => s
          case JArray(items) =>
            items.collectFirst { case JString(s) =>s}.head
        }) // Type Result[String], the map is working over the `JValue` inside Future[JValue] that is held within the Request[JValue]
    someData <- DataService.getData(token,userSessionToken) // Type Result[JValue]
  } yield itemSummaries

  println(restResponse.url) // should print the url of someData, but is instead printing the url of token. restResponse.result is the correct value however

请注意,在此之前,这只是为了理解Future[T],但是这样做我丢失了使用的 URL/参数

4

1 回答 1

1

的规范定义将大致flatMap如下:

def flatMap(f: A => M[B]): M[B]

这本质上是确定性的。在您的情况下,您试图对以非确定性方式给出所需值的操作强加确定性组合。因此,你的麻烦。

如果你想以一种确定的方式回到那个状态,你必须使用Await

def flatMap[B](f: A => Result[B]): Result[B] = Await result (result map f)

这完全完全违背了Future首先使用的目的。描述对象的更好方法是简单地Future从内部移除并从外部包围它:

case class Result(url: String, params: JValue, result: T){
  def map[R](f: T => R) = copy(result = f(result))
  def flatMap[R](f: T => Result[R]) = f(result)
}

因此只有通过应用程序来异步Future评估函数才能进入场景。(String, JValue) => Result[T]

于 2014-05-16T14:50:28.547 回答