Почему Scala предупреждает об удалении типа в первом случае, а не во втором? - PullRequest
10 голосов
/ 22 августа 2011

У меня есть две функции (не они были отредактированы с оригинала - некоторые из ответов ниже отвечают на исходные, которые вернули последовательность ()):

def foo1[A](ls: Iterable[A]) : Iterator[A] =
    for (List(a, b) <- ls sliding 2) yield a

def foo2[A](ls: Iterable[A]) : Iterator[A] =
    for (a::b::Nil <- ls sliding 2) yield a

, которые я наивномысли были одинаковыми.Но Scala дает это убыль только для первого:

warning: non variable type-argument A in type pattern List[A]
is unchecked since it is eliminated by erasure

Я думаю, я понимаю, почему он дает эту ошибку для первого: Scala считает, что я пытаюсь использовать тип в качестве условия нашаблон, то есть совпадение с List[B](_, _) должно завершиться неудачей, если B не наследует от A, за исключением того, что это не может произойти, потому что тип стирается в обоих случаях.

Итак, два вопроса:

1) Почему второй не дает того же предупреждения?

2) Можно ли убедить Scala, что тип на самом деле известен во время компиляции и, следовательно, не может не совпадать?

edit: я думаю, это отвечает моимПервый вопрос .Но мне все еще любопытно по поводу второго.

edit: agilesteel упоминает в комментарии, что

for (List(a, b) <- List(1,2,3,4) sliding 2) yield ()

не выдает предупреждения.Чем это отличается от foo1 (не следует ли стирать параметр [Int] так же, как параметр [A])?

Ответы [ 3 ]

4 голосов
/ 23 августа 2011

Я не уверен, что здесь происходит, но статический тип Iterable[A].sliding равен Iterator[Iterable[A]], а не Iterator[List[A]], который будет статическим типом List[A].sliding.

Вы можете попробовать получить Seq вместо Iterable, и это тоже работает. EDIT Вопреки тому, что я ранее заявлял, и Iterable, и Seq являются ко-вариантами, так что я не знаю, в чем разница. END EDIT Определение sliding тоже довольно странно:

def sliding [B >: A] (size: Int): Iterator[Iterable[A]]

Посмотрите, как для этого требуется B, суперкласс A, который никогда не используется? Сравните это с Iterator.sliding, для которого нет проблем:

def sliding [B >: A] (size: Int, step: Int = 1): GroupedIterator[B]

В любом случае, во втором случае:

for (a::b::Nil <- ls sliding 2) yield a

Здесь вы дважды разбираете список, и для каждой декомпозиции тип head сверяется с A. Поскольку тип head не стирается, у вас нет проблем. Это тоже предположение.

Наконец, если вы превратите ls в List, у вас не будет проблем. Если не считать этого, я не думаю, что ты можешь что-то сделать. В противном случае вы также можете написать это:

def foo1[A](ls: Iterable[A]) : Iterator[A] =
    for (Seq(a, b) <- ls.iterator sliding 2) yield a
2 голосов
/ 23 августа 2011

1) Второй не выдает предупреждение, вероятно, потому что вы строите список (или шаблон), добавляя элементы к объекту Nil, который расширяет List, параметризуя его с помощью Nothing. А так как все Nothing, беспокоиться не о чем;) Но я не уверен, действительно догадываюсь.

2) Почему бы вам просто не использовать:

def foo[A](ls: Iterable[A]) =
    for (list <- ls sliding 2) yield ()
0 голосов
/ 23 августа 2011

Я не очень знаком со Scala, но я использовал Java и Haskell, поэтому я собираюсь выйти на конечность и предположить, что ваш второй пример не совсем то же самое. Похоже, что они оба используют сопоставление с шаблоном для деконструкции первых двух элементов списка, но второй использует оператор cons, а не конструктор List. Я предполагаю, что это как-то связано с взаимодействием с Java и тонкой разницей между тем, как на самом деле функционирует конструктор List и оператор cons.

С другой стороны, возможно, это просто крайний случай, который компилятор упустил из виду, и они оба должны выдать предупреждение.

...