简体   繁体   中英

Lower bound with Currying - simplifiable?

I'd like to wrap exceptions in an own error type leveraging scalazs disjunction.

Following code should compile

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
}

I'd like to keep the curried syntax and don't like to explicitly type MyError .

My current solution is twofold using

  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`
    }
  }

My initial, curried approach would reflect my intention much better, but I can NOT get it working:

  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`
    }
  }

Is a clearer solution possible?

Maybe I am missing some of your intentions but wouldn't this code be much simpler:

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

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

Eg return only an R , finally is just () instead of () => () and no need for type trickery. If you are even willing to dismiss the finally block you can do:

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

In case you want your solution to work you will need this function signature:

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

because \\/ is defined as \\/[+A,+B] . Using the L2 :> L trick is the solution, but you will also need to use the correct return type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM