Can I turn a method which takes an implicit parameter into a function?
trait Tx
def foo(bar: Any)(implicit tx: Tx) {}
foo _ // error: could not find implicit value for parameter tx: Tx
I am trying to achieve the following, preferably if I can somehow make it work with the plain call 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
}
I found this question, however it does not deal with the lifting from methods to functions as far as I can see.
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.
来源:https://stackoverflow.com/questions/16414172/partially-applying-a-function-that-has-an-implicit-parameter