f: ExecutionContext => Materializer => Future[B] => Future[C] is nothing more than a curry function, so you call it f(ec)(mat)(this(a)) with several parameter lists (well, the lists of technical parameters do not belong to the same function, unlike def f(...)(...) , but these are details), In other words, f can be written as:
f: ExecutionContext => { Materializer => { Future[B] => Future[C] } }`
(function that returns a function that returns another function)
Now, if you look at f(ec)(mat)(this(a)) , a call to this(a) will appear, which is defined just above transform :
def apply(value: A)(implicit ec: ExecutionContext, materializer: Materializer): Future[B]
( this(a) is just a call to this.apply(a) ). Now apply has two implicit parameters: ec: ExecutionContext and materializer:Materializer , so to call it like this(a) you need two implicit values. This is what the definition of implicit ec ⇒ implicit mat ⇒ a ⇒ f(ec)(mat)(this(a)) means. It declares ec and mat as implicit for all nested function bodies, so this(a) can pick them up. Another possibility would be to write:
ec ⇒ mat ⇒ a ⇒ f(ec)(mat)(this(a)(ec, mat))
source share