2017-02-17 4 views
4

最初にエラーが発生した後に検証が停止するように、以下の検証関数を記述しようとしています。返品タイプはthreeで、他の機能と異なります。このコードをコンパイルするために使用するモナド・トランスはどれですか?どのMonad Transformerを使用しますか?

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


def one(a : String): Disjunction[Int, String] = 
    a == "one" match { 
    case true => \/-("one") 
    case false => -\/(2) 
    } 

def two(a : String): Disjunction[Int, String] = 
    a == "two" match { 
    case true => \/-("two") 
    case false => -\/(3) 
    } 

def three(a : String): Future[Disjunction[Int, String]] = 
    Future (a == "three") map { 
    case true => \/-("three") 
    case false => -\/(4) 
    } 

def validate(a : String) = for { 
    e1 <- one(a) 
    e2 <- two(a) 
    e3 <- EitherT(three(a)) 
} yield (e1 |+| e2 |+| e3) 

コンパイルエラー:

Error:(27, 7) type mismatch; 
found : scalaz.EitherT[scala.concurrent.Future,Int,String] 
required: scalaz.\/[?,?] 
    e3 <- EitherT(three(a)) 
    ^
Error:(66, 7) type mismatch; 
found : scalaz.EitherT[scala.concurrent.Future,Int,String] 
required: scalaz.\/[?,?] 
    e3 <- EitherT(three(a)) 
    ^
+1

'' future''や ''wait''の' three'の結果に 'one'と' two'をラップしない理由は何ですか? –

+0

あなたは 'EitherT'モナドトランスフォーマーを見たいと思っています.3番目の' < - 'は' String'を返さないので、あなたが望むものではないかもしれない 'Disjunction'全体を与えています(最初の2つは'ストリング(string)」)。 –

+0

@EndeNeu EitherTを試しましたが、まだコンパイルエラーが発生しています。コンパイルエラーとともに更新された質問をご覧ください。私は前にDisjunctionTを使用していました(これはEitherTの単なるラッパーです)。 –

答えて

6

あなたはこのような状況で取ることができ、2つの一般的なアプローチがあります。最初は、すべてのメソッドがあなたが作業していると知っているスタック(この場合はEitherT[Future, Int, ?])を返すようにするか、個々のメソッドが独自のエフェクトを最も正確に取り込むタイプを返すようにして、あなたがそれらを構成するときに適切に得る。

最初のアプローチでは、その使用法がどのように見えるかを正確に知っていれば、構文をより便利にすることができますが、後者の方が柔軟性があり、私の意見では一般に良い選択です。あなたは、for -comprehensionであなたを使用していた昔ながらのFutureを持っていたいくつかの理由で場合

scala> validate("one").run.foreach(println) 
-\/(3) 

scala> validate("x").run.foreach(println) 
-\/(2) 

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

def one(a: String): Disjunction[Int, String] = (a == "one").either("one").or(2) 
def two(a: String): Disjunction[Int, String] = (a == "two").either("two").or(3) 

def three(a: String): EitherT[Future, Int, String] = EitherT(
    Future(a == "three").map(_.either("three").or(4)) 
) 

def validate(a: String) = for { 
    e1 <- EitherT.fromDisjunction[Future](one(a)) 
    e2 <- EitherT.fromDisjunction[Future](two(a)) 
    e3 <- three(a) 
} yield (e1 |+| e2 |+| e3) 

そして:あなたのケースでは、このような何かを見てね.liftM[EitherT[?[_], String, ?]]EitherT[Future, String, A]に持ち上げることができます。

は(それは決して成功しないだろうから、この方法はおそらく(文字列は、"one"に等しいこと"two"と同時に"three"することはできません)、ひどく有用ではありませんが、少なくとも組成がうまくいくことに注意してください。より一般的にモナド変圧器スタックを選択する方法について)

:ちょうど裏返しタイプを回し、Future[Disjunction[Int, ?]]EitherT[Future, Int, ?]になるように、などこの場合具体的には、Futureは(モナド変換子を持っていない、それは通行可能ではありませんし、とにかく、それは内側に行く必要があることを知っているので、ブロックすることなくFutureTを実装することは不可能です)。

2

Travisの回答に(通常通り)追加するものは何もありませんが、この場合はPlayでこれを使用しています!アプリケーション、多分https://github.com/Kanaka-io/play-monadic-actionsいくつかの助けを提供することができます。

関連する問題