18

さまざまなバックエンド システムに対して多くの呼び出しを行うアプリがあり、for 内包表記を使用してバックエンド システム全体のプロセス フローを簡素化したいと考えています。

私は、EitherT (scalaz) と Future (scala 2.10) を組み合わせて、最初の潜在的なエラー (未来またはバックエンド システムの問題) を捕捉し、適切なメッセージをエンド ユーザーに返すことができるようにしようと考えています。私は scalaz Validation をざっと見てきましたが、すべてのエラーではなく最初のエラーをキャプチャするための推奨事項は、EitherT を使用することです。

最初にREPLで簡単な例を試していますが、次のエラーが発生しています

エラー: パラメータ F の暗黙的な値が見つかりませんでした: scalaz.Functor[scala.concurrent.Future]

import scala.concurrent._
import scalaz._
import Scalaz._
import ExecutionContext.Implicits.global

type EitherFuture[+A] = EitherT[Future, String, A]

def method1Success : EitherFuture[Int] = {
  println("method 1 success")
  EitherT {
    Future {
      1.right
    }
  }
}

def method2Failure : EitherFuture[Int] = {
  println("method 2 failure")
  EitherT {
    Future {
      "fail".left
    }
  }
}

val m1 = method1Success

// problem
m1.isRight

// problem
def methodChain1 = {
  for {
    a <- method1Success
    b <- method2Failure
  } yield b
}

私はまだscalaとscalazの両方に慣れていないので、どんなポインタでも素晴らしいでしょう。

** アップデート **

@stew の提案に基づいて scalaz-contrib を含めることにより、さまざまな単純なユースケースのバックエンドの成功、バックエンドの失敗、および将来の失敗を示す、EitherT と Future を組み合わせた for 内包表記を示す更新バージョンができました。

import scala.concurrent._
import scalaz._
import Scalaz._
import ExecutionContext.Implicits.global
import scalaz.contrib._
import scalaz.contrib.std._
import scala.concurrent.duration._

type EitherFuture[+A] = EitherT[Future, String, A]

// various methods that mimic success or different failures
def methodBackendSuccess : EitherFuture[Int] = {
  println("method backend success")
  EitherT {
    Future {1.right}
  }
}

def methodBackendFailure : EitherFuture[Int] = {
  println("method backend failure")
  EitherT {
    Future { "fail".left}
  }
}

def methodFutureFailure : EitherFuture[Int]  = {
  println("method future failure")
  EitherT {
    Future.failed(new Exception("future failed"))
  }
}

// different combinations for for-comprehensions
def methodChainBackendSuccess = {
  for {
    a <- methodBackendSuccess
    b <- methodBackendSuccess
    c <- methodBackendSuccess
  } yield c
}

def methodChainBackendFailure = {
  for {
    a <- methodBackendSuccess
    b <- methodBackendFailure
    c <- methodBackendSuccess
  } yield c
}

def methodChainFutureFailure = {
  for {
    a <- methodBackendSuccess
    b <- methodFutureFailure
    c <- methodBackendSuccess
  } yield c
}

// process results for different chain methods
def processOutcome(chainMethod: => EitherFuture[Int]):Int = try {
    val x = Await.result(chainMethod.run, 30 seconds) 
    x.toEither match {                             
      case Left(l) => {
        println("Backend failure <" + l + ">")
        -1 
      }
      case Right(r) => {
        println("Backend success <" + r + ">") 
        r
      }
    }
  } catch {
    case e: Exception => {
      println("Future error <" + e.getMessage + ">" )
      -99
  }
}

// run tests
val backendSuccess = processOutcome(methodChainBackendSuccess)
val backendFailure = processOutcome(methodChainBackendFailure)
val futureFailure = processOutcome(methodChainFutureFailure)
4

2 に答える 2

6

Future の Functor インスタンスをインポートまたは提供する必要があります。scalaz-contribプロジェクトのものを使用することをお勧めします。-contrib は、scalaz に取り組んでいるのと同じ人々が取り組んでいる別のプロジェクトです。scalaz-core は現時点では scala 2.9 と 2.10 の間の互換性を維持しているため、Future インスタンスは scalaz-core の代わりにこのパッケージに含まれています。

于 2013-07-25T00:40:52.367 に答える
1

の署名を見て、isRightEitherT で定義されています。

def isRight(implicit F: Functor[F]): F[Boolean]

あなたの場合、Future のタイプ パラメーターでパラメーター化された Functor が期待されています。Scalaz は Future 型の暗黙の Functor を提供していません。このモデルに従って独自に記述する必要があります。

http://scalaz.github.io/scalaz/scalaz-2.9.0-1-6.0/doc.sxr/scalaz/Functor.scala.html

サポートされている各タイプのすべての暗黙的な定義に注意してください。

于 2013-07-25T00:26:11.137 に答える