部分应用具有隐式参数的函数

时间:2013-05-07 08:05:54

标签: scala implicit currying partial-application

我可以将一个带隐式参数的方法转换为函数吗?

trait Tx

def foo(bar: Any)(implicit tx: Tx) {}

foo _ // error: could not find implicit value for parameter tx: Tx

我正在努力实现以下目标,最好是我能以某种方式使其与普通电话withSelection(deleteObjects)一起使用:

trait Test {      
  def atomic[A](fun: Tx => A): A

  def selection: Iterable[Any]

  def withSelection(fun: Iterable[Any] => Tx => Unit) {
    val sel = selection
    if (sel.nonEmpty) atomic { implicit tx =>
      fun(sel)(tx)
    }
  }

  object deleteAction {
    def apply() {
      withSelection(deleteObjects)  // !
    }
  }

  def deleteObjects(xs: Iterable[Any])(implicit tx: Tx): Unit
}

我找到了this question,但就我所见,它并没有处理从方法到函数的提升。

2 个答案:

答案 0 :(得分:7)

仅隐含方法。但是你必须将一个函数传递给withSelection。你可以把方法包装在一个函数中来解决:

withSelection(a => b => deleteObjects(a)(b))

无法直接传递deleteObjects因为foo _不适用于定义了隐式参数列表的foo

答案 1 :(得分:4)

据我所知,隐式解决方案必须在使用地点进行,并且不能被理解。我失望的那一刻是当我试图在我的代码中解决'ExecutionContext'扩散时。

我一直在考虑的一个妥协是:

type Async[A] = ExecutionContext => Future[A]

def countFiles(root: String): Async[Int] = implicit ec =>
  // ...

'隐藏'只存在于函数中 - 我们必须在调用时妥协:

implicit class AsyncExt[A](async: Async[A]) {
  def invoke()(implicit ec: ExecutionContext) = async(ec)
}

implicit val ec = ...
countFiles("/").invoke()

另一个妥协 - 我选择并生活的一个让人后悔:

class AsyncFileCounter(ec: ExecutionContext) {
  def countFiles(root: String): Future[A] = ...
}

class FileCounter {
  def async(implicit ec: ExecutionContext) = new AsyncFileCounter(ec)
}

这改变了天真(但需要)的用法:

implicit val ec = ...
val counter = new FileCounter
counter.countFiles("/") // <-- nope

以下内容:

implicit val ec = ...
val counter = new FileCounter
counter.async.countFiles("/") // yep!

根据您的具体情况,这可能是可以忍受的。您可以在我使用'def async'的地方添加'def transactional'。

我确实对此感到遗憾,因为它使继承变得复杂,并且会产生一些分配开销(尽管应该将其JIT消除)。

最重要的是,你必须想出一个更明确的零碎方法来调用你的函数 - 一个不如单独currying的优雅。