Конструктор неунарного типа, ограниченный конструктором унарного типа - PullRequest
1 голос
/ 30 мая 2020

Заголовок пытается описать следующий подтип

implicitly[Map[Int, String] <:< Iterable[(Int, String)]]

Параметр типа A выводится как (Int, String) здесь

def foo[A](cc: Iterable[A]): A = cc.head
lazy val e: (Int, String) = foo(Map.empty[Int, String])

, однако пытается достичь аналогичного эффект с использованием границ параметра типа лучшее, что я могу сделать, это явное указание арности конструктора типа, например,

def foo[F[x,y] <: Iterable[(x,y)], A, B](cc: F[A, B]): (A, B) = cc.head
lazy val e: (Int, String) = foo(Map.empty[Int, String])

, потому что следующие ошибки:

def foo[F[x] <: Iterable[x], A](cc: F[A]) = cc.head
lazy val e: (Int, String) = foo(Map.empty[Int, String])
// type mismatch;
// [error]  found   : A
// [error]  required: (Int, String)
// [error]   lazy val e: (Int, String) = foo(Map.empty[Int, String])
// [error]                                  ^

Следовательно, используя Iterable в качестве верхней границы похоже, нам нужна одна подпись для обработки конструкторов унарных типов Seq и Set, и отдельная подпись для обработки конструкторов типов с двумя арностями Map

def foo[F[x] <: Iterable[x], A](cc: F[A]): A                  // When F is Seq or Set
def foo[F[x,y] <: Iterable[(x,y)], A, B](cc: F[A, B]): (A, B) // When F is Map

Есть ли способ иметь один подпись с использованием границ типа, которая работает для всех трех? Иными словами, как мы могли бы написать, скажем, метод расширения, который работал бы во всех коллекциях?

1 Ответ

1 голос
/ 30 мая 2020

Я думаю, проблема здесь в том, что F установлено на Map, а доброта - это неправильно. Вы должны были бы сказать: у меня есть некий тип X, который расширяет F[A], так что, когда я поднимаю его, я могу использовать его как F[A] - который, в свою очередь, мы хотим быть подтипом Iterable [A ]. Если мы спросим об этом таким образом, это звучит сложно.

Вот почему я лично останусь по адресу:

@ def foo[A](x: Iterable[A]): A = x.head
defined function foo

@ foo(List(1 -> "test"))
res24: (Int, String) = (1, "test")

@ foo(Map(1 -> "test"))
res25: (Int, String) = (1, "test")

"Дайте мне любой x, который является экземпляром Iterable[A] для A ".

Если бы мне пришлось сделать какие-то выводы ... Я бы, вероятно, также go сделал бы таким образом. Я думаю, что это ограничение является причиной того, что CanBuildFrom работает так, как он работает - обеспечение соответствия для части типа сложно, особенно в таких случаях, как Map, поэтому давайте сразу предоставим весь тип в качестве параметра, чтобы ограничить количество выводов необходимо.

...