Understanding function in scala

The question is strictly about Scala syntax, although it does contain some code from akka (as an example).

I am new to Scala. Delving into the akka source code, I came up with the following rather strange method:

def transform[C] (f: ExecutionContext ⇒ Materializer ⇒ Future[B] ⇒ Future[C]): Unmarshaller[A, C] = Unmarshaller.withMaterializer { implicit ec ⇒ implicit mat ⇒ a ⇒ f(ec)(mat)(this(a)) } 

where Unmarshaller.withMaterializer is defined as

  def withMaterializer[A, B](f: ExecutionContext ⇒ Materializer => A ⇒ Future[B]): Unmarshaller[A, B] 

What's going on here? What is the scary function f: ExecutionContext => Materializer => Future[B] => Future[C] . And for me the stranger sequence was implicit s: implicit ec => implicit mat => a => f(ec)(mat)(this(a)) , although withMaterializer has no implicit parameters at all.

What does implicit meaning mean in such sequences?

+6
source share
2 answers

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)) 
+2
source

This is a lambda with curry and implicit parameters (which should be part of the declaration).

The scary syntax is currying : a function of one argument that takes an ExecutionContext and returns another function, one argument that takes a Materializer and returns another function, ... etc. Another thing is implicit arguments .

Here's a simpler example of a similar design:

 implicit val implicitInt: Int = 5 implicit val implicitString: String = "0" val f: Int => String => String = { implicit a => { implicit b => { a.toString + b } } } 

Here f is a curry function that takes an Int and returns a function that takes a String and returns a String . The general syntax for declaring a function value is val f = { argument => ... } , so if you make this argument implicit, it means that there must be an instance of this type in the scope, which will work as the default value. You can apply f to some arguments: f(1)("") , because it is still a function.

You can rewrite the code you are asking about in much more detail by specifying nested functions for each step:

 def transform[C](f: ExecutionContext ⇒ Materializer ⇒ Future[B] ⇒ Future[C]): Unmarshaller[A, C] = { def getExecutionContext(implicit ec: ExecutionContext): Materializer => (A => Future[B]) = { def getMaterializer(implicit mat: Materializer): A => Future[B] = { def applyF(a: A): Future[B] = f(ec)(mat)(this(a)) applyF // : A => Future[B] } getMaterializer // : Materializer => (A => Future[B]) } Unmarshaller.withMaterializer( getExecutionContext // : ExecutionContext => (Materializer => (A => Future[B])) ) } 
0
source

Source: https://habr.com/ru/post/1012087/


All Articles