2013-07-24 4 views
17

私は、さまざまなバックエンドシステムに多くの呼び出しを行い、for-comprehensionsを使用してバックエンドシステム全体のプロセスフローを簡素化することを望んでいるアプリケーションを持っています。いずれかと未来を融合する

EitherT(scalaz)とFuture(scala 2.10)を組み合わせることで、最初の潜在的なエラー(将来またはバックエンドシステムの問題がある場合)をキャプチャし、エンドユーザーに適切なメッセージを返すことができます。私はスカラズ検証をすばやく見てきましたが、最初のエラーをキャプチャするための推奨事項であり、すべてのエラーではなく、EitherTを使用することです。

私は、しかし、私は次のエラーを取得しています、最初のREPLでの簡単な例をしようとしている

エラー:scalaz.Functor [scala.concurrent.Future]

:パラメータFの暗黙的な値を見つけることができませんでした
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と未来が異なるシンプルなユースケースバックエンドの成功を示す組み合わせ、バックエンドで示し更新されたバージョンを持っていますEitherTに定義されたisRightの署名に失敗し、今後の失敗

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) 
+0

「Either」ビジネスがまったく必要ですか? 'Future'はすでに失敗をモデル化することができ、シーケンスにはあなたが望む動作があります。 –

+0

こんにちは@TravisBrown私はまだ私が必要とするかもしれないバックグラウンドの成功、バックエンドの失敗、および将来の失敗をキャプチャし、それらを別々に処理する能力があるかもしれないので、スカラの周りに頭を上げています。私は今、いくつかのコードを入手しました。元の質問を更新し、おそらくそれがEitherTとFutureの組み合わせが必要かどうかを明確にするかもしれません。 –

+1

私はしばらく時間を要したこと:Functor [Future]は、暗黙の実行コンテキストが有効範囲内にある場合にのみ見つけることができます – cvogt

答えて

6

将来のFunctorインスタンスをインポートするか、または提供する必要があります。私はscalaz-contribプロジェクトのものを使用することをお勧めします。 -contribは、同じ人々が仕事をしている独立したプロジェクトです。 scalaz-coreはスケーラ2.9と2.10の間の互換性を維持しているため、Futureインスタンスはscalaz-coreの代わりにこのパッケージに含まれています。

+0

Build.scalaファイルに '' org.typelevel "%%" scalaz-contrib-210 "%" 0.1.4 "'を追加することで、私の例を更新して動作させることができました。コード。 –

1

ルック:

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

それあなたのケースの将来において、あなたのEitherTのタイプパラメータでパラメータ化されたFunctorを期待しています。

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

お知らせサポートされている各タイプのすべての暗黙のDEFS:Scalazはタイプ未来のための暗黙のファンクタを提供していない、あなたはこのモデル独自の次のことを記述する必要があります。

+1

もしScalaz 6を使っていたら、暗黙のdef FutureFunctorを追加するのと同じくらい簡単です:Functor [Future] =新しいFunctor [Future] { def fmap [A​​、B](t:Future [A]、f: 'A => B):Future [B] = t map f }'残念ながら私はScalaz 7を使っています。暗黙のdefが動いたようです。私はScalaz7を見て、何か似たようなことをするべきですか? –