Covariance and variance are flipped to scala

In Scala for the intolerant They say that

functions are inconsistent in their arguments and covariant in type of result

It’s simple and straightforward, but the same topic says

However, inside the parameter of the function, the variance is inverted - its parameters are covariant

and it takes an example foldLeft Iterator method as:

def foldLeft[B](z : B)(op : (B, A) => B) : B 

I do not understand what he is saying.

I tried some blogs as

But there was no clear understanding.

+7
source share
3 answers

A function is always contravariant in its type of argument and covariant in its type of return value, for example,

 trait Function1[-T1, +R] extends AnyRef trait Function2[-T1, -T2, +R] extends AnyRef 

Here T1 , T2 , ..., T n (where n & lt; = 22 ) are arguments, and R is the return type .

In higher-order functions (functions that take a function as an argument), the argument may have a type parameter that is passed to the function, for example, foldLeft in the Iterable line

Iterable declared as

 trait Iterable[+A] extends AnyRef 

and foldLeft are marked as

 def foldLeft[B](z : B)(op : (B, A) => B) : B 

Since A declared covariant, it can be used as the return type. But there is instead an argument type due to

 trait Function2[-T1, -T2, +R] extends AnyRef 

because op : (B, A) => B is the literal type of Function2 .

The key to this is the Function2 trait is contravariant in argument type .

Consequently, the covariance type appears in the method argument due to

trait Function2 is contravariant in its type of argument

This is called a deviation :

  1. The reflection of covariance is a contravariance.
  2. The opposite is covariance.
  3. Flip invariant is an invariant.

Therefore, the invariant can appear in any position (covariance / contravariance)

+4
source

It comes down to what means that one function is a subtype of another. It seems convenient for you that A-> B is a subtype of C-> D if C is a subtype of A (contravariant in input type), and B is a subtype of D (covariant in return type).

Now consider the functions that take other functions as arguments. For example, consider (A-> B) β†’ B. We just apply the same reasoning twice. The argument is a function of type A-> B, and the return type is B. What must be true to provide a function of type C-> B as an input type? Since the functions are contravariant in the input type C-> B, it must be a subtype of A-> B. But, as we discussed in the first paragraph, this means that A must be a subtype of C. So, after two applications of the reasoning in the first in the section we find that (A-> B) β†’ B is covariant in position A.

You can reason similarly to more complex functions. In fact, you have to convince yourself that the position is covariant if it is to the left of the even number of arrows applied to it.

0
source

First, consider the function as a class or, rather, typeclass . Think of its type Function1[-A,+B] Let's say we have the following:

class x
class y extends b

Now I have two functions, such as:

 val test1:x=>Int = //do something val test2:y=>int = //do something 

Now, if I have another method like the following,

def acceptFunction(f: y => Unit, b: B) = //do something

According to a signature of type Function1[-A,+B] I can pass test2 to acceptFunction as well as test1 due to contravariance . A view like test1<:test2 .

This is a completely different thing than using function parameters covariantly. This means that if you have the following,

 class Fruit { def name: String="abstract" } class Orange extends Fruit { override def name = "Orange" } class Apple extends Fruit { override def name = "Apple" } 

You can write the following,

  testM(new Apple()) def testM(fruit:Fruit)={} 

But you cannot write it,

  testM(new Fruit()) def testM(fruit:Apple)={} 
0
source

All Articles