2017-02-06 11 views
2

今日は、私は次のような問題に出くわした警備員: 私はいくつかのパターンマッチングを簡素化はこのように見て、起こっていた:Scalaの非同期とのパターンマッチング(または任意のモナド)は

object Sync { 
    sealed trait MatchType 
    case object BigType extends MatchType 
    case object SmallType extends MatchType 
    case object EvenType extends MatchType 
    case object UnknownType extends MatchType 

    def syncPatternMatch(i: Int): MatchType = i match { 
    case _ if i > 100 => BigType 
    case _ if i < 3 => SmallType 
    case _ if i % 2 == 0 => EvenType 
    case _ => UnknownType 
    } 
} 

を今、残念ながら、私は考え出しました私のガード/エクストラクタはFuture[Boolean]になるでしょう。結果を得るために外部Webサービスを呼び出すとします。 明らかに、未来(またはモナド)でガードまたは抽出パターンを使用することはできません。

ここで、各条件を非同期でチェックしたいが、最初の成功した条件を打破したい。

基本的に私は正常なモナドの流れの反対を望んでいます - 最初の成功で止まることを意味します。
私の実装はうまくいくようですが、もっと簡単な方法があるかどうか、この場合はどのようなパターンを使用するかを調べたいと思っています。

私の例は非常に簡単な例であることを覚えておいてください。 the cats one LIKE '場合モナド'

import cats.data.EitherT 
import cats.implicits._ 
import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.Future 

object Async { 
    sealed trait MatchType 
    case object BigType extends MatchType 
    case object SmallType extends MatchType 
    case object EvenType extends MatchType 
    case object UnknownType extends MatchType 

    type Match[B] = EitherT[Future, MatchType, B] 
    def isBigEnough(i: Int): Match[Unit] = Future(if(i > 100) Left(BigType) else Right(())) 
    def isVerySmall(i: Int): Match[Unit] = Future(if(i < 3) Left(SmallType) else Right(())) 
    def isEven(i: Int): Match[Unit] = Future(if(i % 2 == 0) Left(EvenType) else Right(())) 
    def otherwise: Match[MatchType] = Future.successful(Right(UnknownType)) 

    implicit def liftFutureEither[A, B](f: Future[Either[A, B]]): EitherT[Future, A, B] = EitherT(f) 
    implicit def extractFutureEither[A, B](e: EitherT[Future, A, B]): Future[Either[A, B]] = e.value 

    def asyncPatternMatch(i: Int): Match[MatchType] = for { 
    _ <- isBigEnough(i) 
    _ <- isVerySmall(i) 
    _ <- isEven(i) 
    default <- otherwise 
    } yield default 

    asyncPatternMatch(10).foreach(either => println(either.fold(identity, identity))) 
    // EvenType 
} 

は(ところで。それは2.12スカラ座である)
私は提案のために幸せになる:)

+0

私はあなたがあまりにも多くを考慮したと思います。 'def asyncPatternMatch(i:Future [Int]):Match [MatchType] = i.map(syncPatternMatch)'を試してください。 –

+0

私のガードは非同期ですが、 'isBigEnough'が結果を得るために外部APIを呼び出していると想像してください。 入力としての 'Future [Int]'がここで私をどのように助けてくれるのか、実際は分かりません。 – rincewind

答えて

1

何が必要です。具体的にはFutureの簡略化されたバージョンをロールバックすることができます。

import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

sealed trait MatchType 
object MatchType { 
    case object Big extends MatchType 
    case object Small extends MatchType 
    case object Even extends MatchType 
    case object Unknown extends MatchType 

    def isBigEnough(i: Int): Future[Boolean] = Future successful (i > 100) 
    def isVerySmall(i: Int): Future[Boolean] = Future successful (i < 3) 
    def isEven(i: Int): Future[Boolean] = Future successful (i % 2 == 0) 

    def ifFuture[A](
    test: Future[Boolean], 
    trueCase: => A, 
    falseCase: => Future[A]): Future[A] = 
    test flatMap { t => 
     if (t) Future successful trueCase else falseCase 
    } 

    def apply(i: Int): Future[MatchType] = 
    ifFuture(isBigEnough(i), Big, 
    ifFuture(isVerySmall(i), Small, 
    ifFuture(isEven(i), Even, 
    Future successful Unknown))) 
} 
+1

これはトリックです、ありがとう、 'ifM'の知らなかった – rincewind

+0

@rincewindあなたは大歓迎です。 'ifM'はちょうどモナドのコンビネータであり、私は実際にもっと簡単にそれを実装することができたことを思い出させます。私の答えを更新する。 – Yawar

関連する問題