Partially applying a function that has an implicit parameter

拈花ヽ惹草 提交于 2019-11-30 17:35:35

Implicits only work for methods. But you have to pass a function to withSelection. You can get around by wrapping the method in a function:

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

Its impossible to pass deleteObjects directly because foo _ does not work for a foo with an implicit parameter list defined.

To the best of my knowledge, implicit resolution must take place at usage site, and cannot be curried away. My own moment of disappointment was when I was trying to work around ´ExecutionContext´ proliferation in my code.

One compromise I've been considering was:

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

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

The ´implicit´ only holds within the function -- we have to compromise on invocation:

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

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

Another compromise -- the one I chose and lived to regret:

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

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

This changes the usage from the naive (but desired):

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

To the following:

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

Depending on your context, this could be bearable. You could add a ´def transactional´ where I used ´def async´.

I do regret this however, as it complicates inheritance, and incurs some allocation overhead (though that should be JITed away).

Bottom line is that you'll have to come up with a more explicit piecemeal method of invoking your function -- one that is less elegant than currying alone.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!