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

Почему фильтр должен быть определен для сопоставления шаблонов в цикле for в scala?

Чтобы создать новый класс, который можно использовать в Scala для понимания, кажется, что все, что вам нужно сделать, это определить функцию карты:

scala> class C[T](items: T*) {
     |   def map[U](f: (T) => U) = this.items.map(f)
     | }
defined class C

scala> for (x <- new C(1 -> 2, 3 -> 4)) yield x
res0: Seq[(Int, Int)] = ArrayBuffer((1,2), (3,4))

Но это работает только для простых циклов, где нет совпадений шаблонов в левой части <-. Если вы попытаетесь сопоставить шаблон, вы получите жалобу о том, что метод filter не определен:

scala> for ((k, v) <- new C(1 -> 2, 3 -> 4)) yield k -> v
<console>:7: error: value filter is not a member of C[(Int, Int)]
       for ((k, v) <- new C(1 -> 2, 3 -> 4)) yield k -> v

Зачем нужен фильтр для реализации шаблона? Я бы подумал, что Scala просто переведет вышеуказанный цикл в эквивалентный вызов map:

scala> new C(1 -> 2, 3 -> 4).map{case (k, v) => k -> v}
res2: Seq[(Int, Int)] = ArrayBuffer((1,2), (3,4))

Но это работает нормально, поэтому цикл for должен быть переведен в нечто другое. Для чего это нужно для метода filter?

4b9b3361

Ответ 1

Короткий ответ: согласно спецификациям Scala вам не нужно определять метод "фильтр" для примера, который вы указали, но есть open bug, что означает, что в настоящее время требуется.

Длинный ответ: алгоритм десурагирования, применяемый для понимания, описан в спецификации языка Scala. Начнем с раздела 6.19 "Для понимания и для циклов" (я смотрю версию 2.9 спецификации):

На первом этапе каждый генератор p &lt - e, где p не является неопровержимым (§8.1) для типа e, заменяется на p < - e.withFilter {case p = > true; case _ = > false}

Важным моментом для вашего вопроса является то, является ли шаблон в понимании "неопровержимым" для данного выражения или нет. (Шаблон - бит перед символом '< -'; выражение - бит потом.) Если это "неопровержимо", то файл withFilter не будет добавлен, в противном случае это будет необходимо.

Хорошо, но что означает "неопровержимое"? Перейдите к разделу 8.1.14 спецификации ( "Необычные шаблоны" ). Грубо говоря, если компилятор может доказать, что шаблон не может терпеть неудачу при сопоставлении выражения, тогда шаблон неопровержимый, а вызов withFilter не будет добавлен.

Теперь ваш пример, который работает как ожидалось, - это первый тип неопровержимого шаблона из раздела 8.1.14, шаблон переменной. Поэтому первый пример для компилятора легко определить, что withFilter не требуется.

Второй пример - потенциально третий тип неопровержимого шаблона - шаблон конструктора. Попытка сопоставить (k, v), который равен Tuple2[Any,Any], против Tuple2[Int,Int] (см. Раздел 8.1.6 и 8.1.7 из спецификации)), так как Int неопровержимо для Any. Поэтому второй шаблон также неопровержимый и не требует (не должен) метода withFilter.

В примере Даниэла Tuple2[Any,Any] не является неопровержимым в отношении Any, поэтому добавляются вызовы withFilter.

Кстати, сообщение об ошибке говорит о методе filter, но спецификация говорит о withFilter - он был изменен с помощью Scala 2.8, см. этот вопрос и ответ для подробностей.

Ответ 2

См. разницу:

scala> for ((k, v) <- List(1 -> 2, 3 -> 4, 5)) yield k -> v
res22: List[(Any, Any)] = List((1,2), (3,4))

scala> List(1 -> 2, 3 -> 4, 5).map{case (k, v) => k -> v}
scala.MatchError: 5