【问题标题】:Lower bound with Currying - simplifiable?柯里化的下限 - 可简化?
【发布时间】:2017-03-07 14:11:14
【问题描述】:

我想利用 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`
    }
  }

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

【问题讨论】:

    标签: scala scalaz currying lower-bound


    【解决方案1】:

    也许我错过了你的一些意图,但这段代码不是更简单吗:

    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 块,您可以这样做:

    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 技巧是解决方案,但您还需要使用正确的返回类型。

    【讨论】:

    • 它不能正确推断类型 - 尝试编译上面的示例代码
    • 嗯,我做到了。即使在通常无法推断类型的 IntelliJ 工作表中,它也可以正常工作。 ``` val result = tryCatchIn(e => s"发生异常:${e.getMessage}", println("finally"))(1/0) val result2 = catchMe(e => s"发生异常: ${e.getMessage}")(1/0) ``` 两者都被推断为 String \/ Int.
    • 您是否尝试过我的示例代码,从第 3 行开始,trait Resultobject MyError 等?
    • 再次编辑答案。
    猜你喜欢
    • 2022-11-22
    • 1970-01-01
    • 2011-05-26
    • 2016-01-01
    • 2011-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-04
    相关资源
    最近更新 更多