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

Почему синтаксис Scala для кортежей настолько необычен?

В математике и информатике кортеж представляет собой упорядоченный список элементов. В теории множеств (упорядоченный) n-кортеж представляет собой последовательность (или упорядоченный список) из n элементов, где n - положительное целое число.

Итак, например, в Python 2-й элемент кортежа будет доступен через t[1].

В Scala доступ возможен только через странные имена t._2.

Итак, вопрос в том, почему я не могу получить доступ к данным в кортежах как к последовательности или списку, если это по определению? Есть ли какая-то идея или еще не проверена?

4b9b3361

Ответ 1

Scala знает арифтичность кортежей и, таким образом, может предоставлять аксессоры, такие как _1, _2 и т.д., и создавать ошибку времени компиляции, если вы выбрали _3 для пары, например, Более того, тип этих полей является тем, что тип, используемый как параметр для Tuple (например, _3 на Tuple3[Int, Double, Float], вернет a Float).

Если вы хотите получить доступ к n-му элементу, вы можете написать tuple.productElement(n), но тип возвращаемого значения может быть только Any, поэтому вы теряете информацию о типе.

Ответ 2

Я считаю, что следующий отрывок из "Программирование в Scala: всестороннее пошаговое руководство" (Мартин Одерски, Лекс Лоун и Билл Веннерс) напрямую затрагивает оба ваших вопроса:

Доступ к элементам кортежа

Возможно, вам интересно, почему вы не можете получить доступ к элементам кортежа, например элементы списка, например, с "pair (0)". Причина в том, что что метод применения списка всегда возвращает тот же тип, но каждый элемент кортежа может быть другого типа: _1 может иметь один результат тип, _2 другой и т.д. Эти числа _N являются однонаправленными, вместо этого от нуля, потому что начиная с 1 - это традиция, установленная другими языки со статически типизированными кортежами, такими как Haskell и ML.

Scala кортежи получают очень незначительное предпочтение в отношении синтаксиса языка, кроме выражений '(' a1, ..., an ')', обрабатываемых компилятором как псевдоним для scala.Tuplen(a1,..., an) класса. В противном случае кортежи ведут себя как любые другие объекты Scala, фактически они написаны в классах Scala как которые варьируются от Tuple2 до Tuple22. Tuple2 и Tuple3 также известны под псевдонимами Pair и Triple соответственно:

 val a = Pair   (1,"two")      // same as Tuple2 (1,"two") or (1,"two") 
 val b = Triple (1,"two",3.0)  // same as Tuple3 (1,"two",3.0) or (1,"two",3.0)

Ответ 3

Одно большое различие между List, Seq или любым набором и кортежем состоит в том, что в кортеже каждый элемент имеет свой собственный тип, где в List все элементы имеют один и тот же тип.

И как следствие, в Scala вы найдете классы типа Tuple2[T1, T2] или Tuple3[T1, T2, T3], поэтому для каждого элемента у вас также есть параметр типа. Коллекции принимают только один параметр типа: List[T]. Синтаксис, подобный ("Test", 123, new Date), - это просто синтаксический сахар для Tuple3[String, Int, Date]. И _1, _2 и т.д. - это только поля на кортеже, которые возвращают соответствующий элемент.

Ответ 4

Вы можете легко достичь этого с помощью shapeless:

import shapeless.syntax.std.tuple._

val t = ("a", 2, true, 0.0)

val s = t(0) // String at compile time
val i = t(1) // Int at compile time
// etc

Множество методов, доступных для стандартной коллекции, также доступно для кортежей таким образом (head, tail, init, last, ++ и ::: для конкатенации +: и :+ для добавления элементов, take, drop, reverse, zip, unzip, length, toList, toArray, to[Collection],...)

Ответ 5

При нормальном доступе к индексу любое выражение может быть использовано, и для проверки на compiletime потребуется некоторое серьезное усилие, если результат выражения индекса гарантированно находится в зоне действия. Сделайте это атрибутом, и ошибка времени компиляции для (1, 2)._3 следует за "бесплатно". Вещи, подобные разрешению только целочисленных констант внутри доступа к элементам на кортежах, были бы очень особенным случаем (уродливым и ненужным, некоторые говорили бы смешно) и снова некоторые работы для реализации в компиляторе.

Python, например, может уйти от этого, потому что он не сможет (не может) проверить (в compiletime, то есть), если индекс все равно находится в зоне.

Ответ 6

Я думаю, что для проверки типов. Как говорит Делнан, если у вас есть кортеж t и индекс e (произвольное выражение), t(e) не даст компилятору никакой информации о том, к какому элементу обращаются (или даже если он является допустимым элементом для кортежа такого размера). Когда вы обращаетесь к элементам по имени поля (_2 - действительный идентификатор, это не специальный синтаксис), компилятор знает, к какому полю вы обращаетесь и какому типу он принадлежит. Языки, подобные Python, на самом деле не имеют типов, поэтому для них это не нужно.

Ответ 7

Помимо преимуществ, которые Жан-Филипп Пелле уже упомянул, эта нотация также очень распространена в математике (см. http://en.wikipedia.org/wiki/Tuple). Многие лекторы добавляют индексы к кортевым переменным, если они хотят ссылаться на элементы кортежа. И общая (LaTeX) запись для записи "с индексом n" (относящаяся к n-му элементу кортежа) равна _n. Поэтому я нахожу это на самом деле очень интуитивным.