나는 Future [Either [String, A]] 유형을 반환하는 여러 함수를 사용하는 코드를 정리하려고했습니다.Scalaz 7에서 EitherT를 사용할 때 Monad [Future]에 대한 실행 컨텍스트 지정
이러한 기능은 미래를 정점으로보고 나서 내부에서 절충해야하는 문제 때문에 이해하기 쉽도록 구성되지 않습니다. EitherT 모나드 변압기를 사용한 후에는 EitherT를 사용하여 좋아하는 솔루션을 찾았습니다. 둘 중 하나를 추가해야하고 최종 결과를 얻을 때 '실행'을 호출하는 추가 단계가 필요하지 않은 경우에도 이상적이지는 않습니다.
내 솔루션은 만족스럽지 않지만 한 가지 사실은 두 T가 작동하려면 Monad[Future]
을 만들어야한다는 것입니다. 실행 컨텍스트가 필요합니다. 그렇게 할 분명한 방법은 없습니다. 내가 한 것은 내 코드의 범위에서 암시 적 실행 컨텍스트를 갖고 동일한 실행 컨텍스트를 전달하는 Future Monad를 작성하여 두 코드가 동일한 실행 컨텍스트를 사용하도록하는 것입니다. 이것은 조금 혼란스럽고 오류가 발생하기 쉬운 것 같습니다.
더 좋은 방법이 있으면 알려주세요. 어렵게해야
implicit def MWEC(implicit ec: ExecutionContext): Monad[Future] = ???
이 방법은 섞어 실행 컨텍스트 :
/*
Example of EitherT in ScalaZ
val scalaZVersion = "7.2.8"
"org.scalaz" %% "scalaz-core" % scalaZVersion,
"org.scalaz" %% "scalaz-effect" % scalaZVersion,
*/
import java.util.concurrent.Executors
import scala.concurrent.duration._
import org.scalatest._
import scala.concurrent.{Await, ExecutionContext, Future}
import scalaz.{-\/, Monad, \/, \/-}
import scalaz.EitherT.eitherT
object MonadFutureUtil {
// a Future Monad with a specific instance of an EC
case class MonadWithExecutionContext()(implicit ec : ExecutionContext) extends Monad[Future] {
def point[A](a: => A): Future[A] = Future(a)
def bind[A, B](fa: Future[A])(f: (A) => Future[B]): Future[B] = fa flatMap f
}
}
class TestFutureUtil extends FlatSpec with Matchers with OptionValues with Inside with Inspectors {
implicit val ec = new ExecutionContext {
implicit val threadPool = Executors.newFixedThreadPool(8)
def execute(runnable: Runnable) {
threadPool.submit(runnable)
}
def reportFailure(t: Throwable): Unit = {
println(s"oh no! ${t.getMessage}")
}
}
implicit val monadicEC = MonadFutureUtil.MonadWithExecutionContext()(ec)
// halves the input if it is even else fails
def dummyFunction1(n: Int)(implicit ec : ExecutionContext) : Future[\/[String, Int]] = {
Future.successful(
if(n % 2 == 0)
\/-(n/2)
else
-\/("An odd number")
)
}
// appends a suffix to the input after converting to a string
// it doesn't like numbers divisible by 3 and 7 though
def dummyFunction2(n: Int)(implicit ec : ExecutionContext) : Future[\/[String, String]] = {
Future.successful(
if(n % 3 != 0 && n % 7 != 0)
\/-(n.toString + " lah!")
else
-\/(s"I don't like the number $n")
)
}
"EitherFuture" should "add the results of two dummyFunction1 calls" in {
val r = for (
rb1 <- eitherT(dummyFunction1(8));
rb2 <- eitherT(dummyFunction1(12))
) yield (rb1 + rb2)
r.run.map {
_ shouldBe \/-(11)
}
}
it should "handle functions with different type" in {
val r = for (
rb1 <- eitherT(dummyFunction1(14));
rb2 <- eitherT(dummyFunction1(12));
rb3 <- eitherT(dummyFunction2(rb2 + rb1))
) yield rb3
val r2 = Await.result(r.run.map {
case \/-(s) =>
(s == "13 lah!")
case -\/(e) =>
false
}, 5 seconds)
assert(r2)
}
it should "doesn't like divisible by 7" in {
val r = for (
rb1 <- eitherT(dummyFunction1(14));
rb2 <- eitherT(dummyFunction1(14));
rb3 <- eitherT(dummyFunction2(rb1 + rb2))
) yield rb3
val r2 = Await.result(r.run.map {
case \/-(s) =>
false
case -\/(e) =>
true
}, 5 seconds)
assert(r2)
}
}