2

ディスパッチ結果をリクエストに使用される URL とパラメータでラップする次のモナドを scala に実装しました。

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が正しいためには、とurlparamsから来ている必要がありfますf: T => Result[S]。上記の例では、正常にコンパイルされ、署名はまさに私が必要としているものですが、self.urlandは、 andがedで更新されていないことをself.params意味します。つまり、 and変数を取得する方法がわかりませんが呼び出されているときのアプリケーションから。urlparamsResultflatMapurlparamfflatMap

にはTが必要ですが、 andにRequest[S]は必要ありません。適切に定義できるように をから分離するスカラの方法は何でしょうか?urlparamsurl,paramsresultflatMap

注: モナドの背後にある一般的な目的はHTTP、ディスパッチ (つまりFuture[T]) の結果を処理しながら、 を更新してリクエストに使用できるようにすることurlです。を変更しますparamsflatMapsurlparamsresultresult

編集:これは私が現在モナドをどのように使用しているかの例です

  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 に答える