3

Retry Execution の戦略を組み合わせるために Monoid を作成しており、RetryExecutor[T] がベースの型です。次の基本型とモノイドを定義しました。

trait RetryExecutor[C] {
  def retry[T](f: C => T)(context: C): T

  def predicate: Option[Throwable]
  def application: Unit
  val retryEligible: PartialFunction[Throwable, Boolean]
}

object RetryExecutor {
  implicit def retryExecutorMonoid[A] = new Monoid[RetryExecutor[A]] {
  ...
}

および次のようないくつかの基本型:

case class LinearDelayingRetryExecutor[C](delayInMillis: Long)(val retryEligible: PartialFunction[Throwable, Boolean]) extends RetryExecutor[C] {
  override def predicate: Option[Throwable] = None
  override def application = Thread.sleep(delayInMillis)
}

case class RetryWithCountExecutor[C](maximumRetries: Int)(val retryEligible: PartialFunction[Throwable, Boolean])(implicit val logger: Logger) extends RetryExecutor[C] {
  var remainingTries = maximumRetries + 1

  override def application: Unit = {
    remainingTries = remainingTries - 1
  }

  override def predicate: Option[Throwable] = {
    if (remainingTries > 0) None
      else Some(RetryingException("Retry count of " + maximumRetries + " exceeded for operation"))
  }
}

そして、それらを手動で組み合わせることができます:

val valid: PartialFunction[Throwable, Boolean] = { case x: TestException => true }

val monoid = RetryExecutor.retryExecutorMonoid[Int]
val x = monoid.append(RetryWithCountExecutor[Int](3)(valid), LinearDelayingRetryExecutor(100)(valid))

しかし、追加演算子を使用しようとすると:

val x = RetryWithCountExecutor[Int](3)(valid) |+| LinearDelayingRetryExecutor(100)(valid)

コンパイル エラーが発生します。

[error] /Users/1000306652a/work/src/test/scala/com/foo/bar/RetryExecutorSpec.scala:25: value |+| is not a member of com.foo.bar.retry.RetryWithCountExecutor[Int]
[error]   val k: RetryExecutor[Int] = RetryWithCountExecutor[Int](3)(valid) |+| BackingOffRetryExecutor[Int](100)(valid)
4

1 に答える 1

5

はるかに単純なケースで同じ問題を次に示します。

scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._

scala> Option(1) |+| Option(2)
res0: Option[Int] = Some(3)

scala> Monoid[Option[Int]].append(Some(1), Some(2))
res1: Option[Int] = Some(3)

scala> Some(1) |+| Some(2)
<console>:14: error: value |+| is not a member of Some[Int]
              Some(1) |+| Some(2)
                      ^

問題 (これは実際には問題ではなく、より設計上の決定です) は、Monoid共変ではMonoid[Option[Int]]ないことMonoid[Some[Int]]です。

理想的な解決策は、値の型をスーパータイプとして返​​すサブタイプのコンストラクターを提供することです。例を続けるOptionと、Scalaz はこれらのコンストラクターを および として提供しsomeますnone

scala> some(1) |+| some(2)
res3: Option[Int] = Some(3)

scala> some(1) |+| none
res4: Option[Int] = Some(1)

もちろん、値を明示的にアップキャストすることもできますが、サブタイプをそのように使用することを避けることができれば人生はずっと単純になります。

于 2014-10-03T19:05:24.497 に答える