Почему синтаксис Scala для кортежей такой необычный? - PullRequest
69 голосов
/ 30 июля 2011

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

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

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

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

Ответы [ 7 ]

90 голосов
/ 30 июля 2011

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

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

33 голосов
/ 26 ноября 2011

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

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

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

Кортежи Scala получают очень небольшую преференциальную обработку в том, что касается синтаксиса языка, кроме выражений '(' a1, ..., an ')', которые обрабатываются компилятором как псевдоним для scala.Tuplen ( a1, ..., * 1013) *) экземпляр класса. В противном случае кортежи ведут себя как любые другие объекты Scala, фактически они записываются в Scala как case-классы, которые варьируются от 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)
20 голосов
/ 30 июля 2011

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

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

12 голосов
/ 19 июля 2014

Вы можете легко достичь этого с бесформенным :

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], ...)

7 голосов
/ 30 июля 2011

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

7 голосов
/ 30 июля 2011

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

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

0 голосов
/ 21 июля 2014

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

...