Подтвердить что ты не робот

В Scala, почему я получаю это "полиморфное выражение не может быть создано для ожидаемого типа"?

Почему в Scala 2.9.0.1?

происходит следующее:
scala> def f(xs: Seq[Either[Int,String]]) = 0
f: (xs: Seq[Either[Int,String]])Int

scala> val xs = List(Left(0), Right("a")).iterator.toArray
xs: Array[Product with Serializable with Either[Int,java.lang.String]] = Array(Left(0), Right(a))

scala> f(xs)
res39: Int = 0

scala> f(List(Left(0), Right("a")).iterator.toArray)
<console>:9: error: polymorphic expression cannot be instantiated to expected type;
 found   : [B >: Product with Serializable with Either[Int,java.lang.String]]Array[B]
 required: Seq[Either[Int,String]]
       f(List(Left(0), Right("a")).iterator.toArray)
                                            ^

Обновление: Дебильски предлагает лучший пример (не на 100% уверен, что это демонстрирует одно и то же основное явление):

Seq(0).toArray : Seq[Int] // compiles
Seq(Some(0)).toArray : Seq[Option[Int]] // doesn't
4b9b3361

Ответ 1

Лучшим человеком, который объяснит это, является Adriaan Moors, и он уже сделал это здесь, на Qaru - найти ответы от него, и вы его найдете.

В любом случае проблема заключается в том, что тип List(Left(0), Right("a")).iterator.toArray не может быть выведен в пределах границ, ожидаемых f. Он не соответствует Seq[Either[Int, String]] без неявного преобразования, и не может быть применено неявное преобразование, потому что оно (тип) не может быть определено. Это как проблема с яйцом и курицей.

Если вы используете <% или присваиваете его значению val, вы прерываете цикл в выводе.

Ответ 2

Это не имеет никакого отношения к Either, а скорее к обработке Array. Если вы преобразуете его вручную в Seq, он работает:

scala> f(xs.toSeq)
res4: Int = 0

A Scala Array не является Seq (потому что это фактически массив Java). Но a WappedArray есть. Вы также можете переопределить свою функцию f:

scala> def f[A <% Seq[Either[Int,String]]](xs: A) = 0
f: [A](xs: A)(implicit evidence$1: (A) => Seq[Either[Int,String]])Int

scala> f(xs)
res5: Int = 0

Кстати, не нужно получать итератор перед вызовом toArray.

Ответ 3

Я считаю, что это связано с тем, что вы не можете превратить Array в массив, но вы можете преобразовать последовательность в массив. Метод хочет, чтобы Sequence использовалась для создания массива.

Нижняя строка - проверить сигнатуры метода и не угадать, на чем они основаны на имени метода.

Важная часть:

found   : [B >: Product with Serializable with Either[Int,java.lang.String]]Array[B]
 required: Seq[Either[Int,String]]
       f(List(Left(0), Right("a")).iterator.toArray)

В методе toArray требуется Seq (так что List будет в порядке), и он возвращает массив. Вы передали ему массив, и он не знает, что делать. Либо сначала создайте массив в Seq, либо просто пропустите метод toArray.

Если вы вернетесь на один шаг, становится ясно, что метод iterator принимает ваш список и возвращает массив. Каждый вызов метода является вызовом функции.