1

我想利用scalazs析取将异常包装在自己的错误类型中。

以下代码应编译

trait Result
trait Error extends Result
object MyError extends Error
object OK extends Result

val r: Error \/ OK.type = tryCatchIn(_ => MyError /*:Error*/) {
  val result: Error \/ OK.type = ???
  result
}

我想保留柯里化语法并且不喜欢显式键入MyError.

我目前的解决方案是双重使用

  def tryCatchIn2[L, R](exceptionTransformer: Throwable => L, `finally`: => Unit = () => ()): CatchFinally[L] = {
    new CatchFinally(exceptionTransformer, `finally`)
  }

  class CatchFinally[L](val exceptionTransformer: Throwable => L, `finally`: => Unit = () => ()) {
    def apply[L2 >: L, R](block: => L2 \/ R): L2 \/ R = try {
      block
    } catch {
      case NonFatal(e) => -\/(exceptionTransformer(e))
    } finally {
      `finally`
    }
  }

我最初的咖喱方法会更好地反映我的意图,但我无法让它发挥作用:

  def tryCatchIn[L, R, L2 >: L](exceptionContainer: Throwable => L, `finally`: => Unit = () => ())
                               (block: => L2 \/ R): L2 \/ R = {
    try {
      block
    } catch {
      case NonFatal(e) => -\/(exceptionContainer(e))
    } finally {
      `finally`
    }
  }

是否有更清晰的解决方案?

4

1 回答 1

0

也许我错过了你的一些意图,但这段代码不会简单得多:

def tryCatchIn[L, R](exceptionContainer: Throwable => L, `finally`: => Unit = ())
                         (block: => R): L \/ R = {

    try {
        \/-(block)
    } catch {
        case NonFatal(e) => -\/(exceptionContainer(e))
    } finally {
       `finally`
    }
}

例如,只返回一个R, finally 只是()代替() => ()并且不需要类型诡计。如果您甚至愿意解除 finally 块,您可以执行以下操作:

def catchMe[L,R](exceptionContainer: Throwable => L)(block: =>  R) : L \/ R = {
   Try {block}.toDisjunction.leftMap(exceptionContainer)
}

如果您希望您的解决方案正常工作,您将需要此函数签名:

def tryCatchIn[L, R, L2 >: L](exceptionContainer: Throwable => L2, `finally`: => Unit = () => ())
                         (block: => L \/ R): L2 \/ R 

因为\/被定义为\/[+A,+B]。使用L2 :> L技巧是解决方案,但您还需要使用正确的返回类型。

于 2017-03-10T10:21:58.957 回答