Дисперсионная функция карты списка Scala - PullRequest
0 голосов
/ 07 декабря 2018

У меня есть вопрос, который меня беспокоит.Списки в Scala являются ковариантными (List[+A])

Допустим, у нас есть следующие классы:

class A  
class B extends A

Функция map из List[B] принимает функцию f: B => C

Но я также могу использовать f: A => C, который является подклассом f: B => C
, и это полностью имеет смысл.

В настоящее время меня смущает то, что функция map должна приниматьтолько функции, которые являются суперклассами исходной функции (поскольку функции противоречивы по своим аргументам), что не применимо в приведенном мной примере.

Я знаю, что с моей логикой что-то не так, и я хотел быпросветленный.

Ответы [ 2 ]

0 голосов
/ 07 декабря 2018

Ваша ошибка заключается в предположении, что map(f: A => C) должен принимать только функции, которые являются суперклассами A => C.

В то время как в действительности map будет принимать любую функцию, которая является подклассом A => C.

В Scala параметр функции всегда может быть подклассом требуемого типа.

Ковариация A в List[A] говорит только о том, чтовезде, где требуется List[A], вы можете указать List[B], если B <: A.

Или, проще говоря: List[B] можно рассматривать как подкласс List[A].

Я собрал небольшой пример, чтобы объяснить эти два поведения:

class A  
class B extends A

// this means: B <: A

val listA: List[A] = List()
val listB: List[B] = List()

// Example 1: List[B] <: List[A]
// Note: Here the List[+T] is our parameter! (Covariance!)

def printListA(list: List[A]): Unit = println(list)

printListA(listA)
printListA(listB)

// Example 2: Function[A, _] <: Function[B, _]
// Note: Here a Function1[-T, +R] is our parameter (Contravariance!)

class C

def fooA(a: A): C = ???
def fooB(b: B): C = ???

listB.map(fooB)
listB.map(fooA)

Попробуйте!

Надеюсь, это поможет.

0 голосов
/ 07 декабря 2018

Как вы уже подозревали, вы тут все путаете.

С одной стороны, у вас есть List[+A], который говорит нам что-то об отношениях между List[A] и List[B], учитывая отношения между A и B.Тот факт, что List является ковариантным в A, означает, что List[B] <: List[A], когда B <: A, как вы уже знаете,

С другой стороны, List подвергает метод mapизменить его «содержимое».Этот метод на самом деле не заботится о List[A], а только о A с, поэтому дисперсия List здесь не имеет значения.Ситуация, которая вас смущает, заключается в том, что существует некоторая подтипировка, которую необходимо принять во внимание: map принимает аргумент (A => C в данном случае, но это не совсем актуально) и, как обычно, с методами и функциямиВы всегда можете заменить его аргумент чем-либо, что является его подтипом.В вашем конкретном случае любой AcceptedType будет в порядке, пока AcceptedType <: Function1[A,C].Здесь имеет значение дисперсия Function, а не List.

...