在scala中将任何方法转换为可重试的方法

时间:2018-01-03 08:51:09

标签: scala functional-programming

我正在尝试实现一个应该采用任意方法或代码块的方法,它应该将方法或代码块转换为可重试的方法。

以下示例旨在演示我需要的内容

import scala.util.{Try,Success,Failure}

object Retry {
    retry[A, B](f: A => Try[B], r: Int): A => Try[B] = {
        // return a function g and when g is invoked with parameters
        // f should be tried (if failed) r number of time otherwise
        // result of first successful execution of f should be returned
        // from g. retry should work with any arbitrary function with
        // any number/type of parameters
    }
}

2 个答案:

答案 0 :(得分:2)

如果你想抽象优于arity,这是非常先进的,你将不得不使用shapeless,一个用于泛型编程的库。

以@ chengpohi的答案为基础:

import shapeless._, ops.function._
import scala.util.Try

def retry[F, L <: HList, R](f: F, r: Int = 1)(implicit fnToP: FnToProduct.Aux[F, L => R], fnFromP: FnFromProduct.Aux[L => R, F]): F = {
  val fn = fnToP(f)
  def repeat(a: L): R = {
    for (_ <- 0 to r) {
      val tried = Try(fn(a))
      if (tried.isSuccess) {
        return tried.get
      }
    }
    throw new RuntimeException(s"retry $r failed")
  }
  fnFromP(repeat _)
}

有效:

scala> var i = 0
i: Int = 0

scala> val f = retry( (a: Int) => if (i < 10) {i += 1; println(s"try $i"); throw new RuntimeException} else a * 3, 42)
f: Int => Int = shapeless.ops.FnFromProductInstances$$anon$2$$Lambda$1489/1404497488@1d49a23c

scala> f(5)
try 1
try 2
try 3
try 4
try 5
try 6
try 7
try 8
try 9
try 10
res4: Int = 15

scala> var i = 0
i: Int = 0

scala> val f = retry( (a: String, b: Int) => if (i < 10) {i += 1; println(s"try $i"); throw new RuntimeException} else a * b, 42)
f: (String, Int) => String = shapeless.ops.FnFromProductInstances$$anon$3$$Lambda$1492/121867201@1a22b89c

scala> f("foo", 5)
try 1
try 2
try 3
try 4
try 5
try 6
try 7
try 8
try 9
try 10
res5: String = foofoofoofoofoo

答案 1 :(得分:0)

  def retry[A, B](f: A => B, r: Int = 1): A => B = {
    def repeat(a: A): B = {
      for (_ <- 0 to r) {
        val tried = Try(f(a))
        if (tried.isSuccess) {
          return tried.get
        }
      }
      throw new RuntimeException(s"retry $r failed")
    }
    repeat
  }

有一种简单的方法可以执行此操作,try如果成功返回,否则throw Exception