LINUX.ORG.RU

кортежи не нужны?

 


0

1

Вот мне всегда казалось, что кортежи - это лишнее понятие. Сейчас копаюсь в потрохах SBCL и вижу, насколько они усложняют вывод типов и систему типов. Скажем так, более чем вдвое. В Си можно можно просто определить struct. Можно его инициализировать двумя значениями в красивой форме

struct gasket {
    float weight;
    unsigned height;
    unsigned diameter;
};
 
void main() {
    struct gasket obj = { 12.f, 120, 30 };

Можно вернуть структуру из функции, можно передать в функцию. Спрашивается, а зачем тогда кортежи? Что нового они вообще дают хоть в каком-то языке? Понятно, что в языках, где список может состоять из элементов только одного типа, и где нет типа any/t/variant, кортежи могут быть кривым костылём для полиморфных списков. Ну и теоретически они могут быть эффективнее. Но Си всё равно даёт то же самое, плюс поля кортежа ещё и именованные. Единственное неудобство - это то, что тип структуры нужно объявлять. Но в этом можно видеть плюс, т.к. объявление структуры заставляет дать вещам имена и тем самым сделать программу более явной и понятной. А типизация полей структуры убережёт от ошибок.

Единственное, что я заметил - так это то, что времена жизни, константность и прочие атрибуты объектов в кортеже никак не связаны, а в структуре - связаны. Но если структура наполнена указателями, то и это почти не имеет значения.

Что я упустил?

★★★★★

Спрашивается, а зачем тогда кортежи?

Потому что их состав можно конструировать/определять/работать динамически :-) Т.е. во времена рантайма или компайл-тайма, соответственно, в зависимости от языка :-) Например, в цепепе есть std::tuple - динамика во время компайл-тайма :-) Не забывай, что в цепепе во время компиляции доступен лишь убогий язык шаблонов, а не весь цепепе, как, например, в макрах Лиспа, где во время компайл-тайма можно делать всё что угодно, а не только жонглировать с типами, пихая их в разные шаблоны, дабы добиться какого-то эффекта во время компайл-тайма :-)

anonymous ()

Дык кортеж и структура это одно и то же, разве нет?

vladimir-vg ★★ ()

В питоне кортежи фактически являются неизменяемыми списками (хотя у них тоже могут быть именованные поля). Поэтому их можно передавать по ссылке, не боясь, что их кто-нибудь изменит. Если для всех элементов определено равенство и хэш, то и для кортежа тоже будет автоматически определено равенство и хэш, поэтому его можно будет использовать, например, в качестве ключа в словаре.

Примерным аналогом в Си будет const struct.

Но в принципе да, если в языке есть структуры, массивы и объявление неизменяемости, то кортежи не нужны.

proud_anon ★★★★★ ()

Вот мне всегда казалось, что кортежи - это лишнее понятие. Что я упустил?

Что есть экзотические языки, типа OpenEuphoria ©, где кортежи - это базовый тип.

кортежи могут быть кривым костылём для полиморфных списков. Ну и теоретически они могут быть эффективнее. Но Си всё равно даёт то же самое, плюс поля кортежа ещё и именованные.

Ага, для OpenEuphoria это одна из задач, решаемых на несколько более высоком уровне абстракции, чем Си, но в конечном итоге, всё транслируется в Си.

quickquest ★★★★★ ()

Сделай в своём Яре динамически определяемые во рантайме кортежи :-) Объясню зачем :-) Представь, что понадобилось динамически мапнуть результат такого банального SQL-запроса — select * from foo :-) В случае со структурами, определяемыми вручную, нужно будет переопределять структуру Foo всякий раз при изменении таблицы foo :-) А вот в случае с кортежами - нет :-)

anonymous ()

Это которые Tuple? Нужны на уровне языка!

RazrFalcon ★★★★★ ()

Кортежи - это структуры без именования членов. Больше никакой разницы нет. Поэтому в общем случае они не нужны, так как уступают структурам, никаких преимуществ не имея. В частных, как-то генерируемые на этапе компиляции типы где названия будут только мешаться, могут быть удобнее.

anonymous ()

Нужны когда лень объявлять отдельный тип

anonymous ()

Что я упустил?

Я хз как там в CL с кортежами, но в python их крутость в том, что ты можешь распаковать кортеж в конкретные переменные. Вот так:

foo, baz, bar = some_record

такой паттерн матчинг довольно удобен. И да, то, что не нужно объявлять тип кортежа это тоже больше преимущество.

Остальное, лично для меня, не существенно. Т.е. если бы в языке были только списки, но с поддержкой тех двух фич, что я описал выше, то для меня никакой разницы не было бы вообще.

Norgat ★★★★★ ()

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

vertexua ★★★★★ ()
Ответ на: комментарий от vertexua

Не только zip, а вообще для любых итераторов, возвращающих не одно значение.

RazrFalcon ★★★★★ ()
Ответ на: комментарий от Norgat

распаковать кортеж в конкретные переменные

root# python
Python 2.7.6 (default, Jun 22 2015, 18:00:18) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a, b, c = [1, "foo", {}]
>>> a, b, c
(1, 'foo', {})
>>> 
Virtuos86 ★★★★★ ()

Никто не написал, а я напишу.

Как, по-твоему, гоферы без кортежей будут ошибки обрабатывать?

Virtuos86 ★★★★★ ()
Ответ на: комментарий от RazrFalcon

Ну и слава Аллаху.

P.S. Правда это будет не так, т.к. легаси и году к 20 хорошо если многие проекты переползут на C++14 стандарт полноценно.

Norgat ★★★★★ ()
Последнее исправление: Norgat (всего исправлений: 1)
Ответ на: комментарий от Norgat

В CL так: кортежей как отдельного типа данных не существует. Ты можешь:

  • вернуть кортеж из выражения
  • разбросать кортеж по переменным
  • превратить кортеж в список и список в кортеж
  • объявлять тип каждого элемента в кортеже

    И зияет дыра - нельзя специфицировать количество элементов в кортеже. При присваивании лишние элементы выбрасываются, недостающие заменяются nil-ами.

den73 ★★★★★ ()
Последнее исправление: den73 (всего исправлений: 2)
Ответ на: комментарий от RazrFalcon

Уже можно. В 17 стандарте разрешили распаковку структур. Хотя не знаю, относится ли это к кортежам)

sm4ll_3gg ()
Ответ на: комментарий от den73

И зияет дыра - нельзя специфицировать количество элементов в кортеже. При присваивании лишние элементы выбрасываются, недостающие заменяются nil-ами.

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

В таких ЯП поддержка кортежей выливается в адские макароны (см. F# исходники, например).

Norgat ★★★★★ ()
Ответ на: комментарий от den73

Поржал:

-- Euphoria is innovative 
while 1 label "families" do 
  while 1 do -- labels are optional 
    while 1 label "children" do 
      exit "families" -- exit top level while 
    end while 
  end while 
end while 
Это из стандарта CL от 90-го года. Впрочем, тогда Яр тоже is innovative. Ты имеешь в виду, что кортежи в эйфории - это sequence?

den73 ★★★★★ ()
Ответ на: комментарий от den73

Вот код на Яре для сравнения (тема не про то, но не смог смолчать, видя сию «инновационность»):

цикл имя Семьи тело
  цикл тело -- по умолчанию цикл имеет имя Цикл
    цикл имя Дети тело
      // Яр is even more innovative
      вернуть-из(Семьи,1) // ещё и возвращаем значение
    кнц кнц кнц // можно все три записать на одной строче

den73 ★★★★★ ()
Ответ на: комментарий от den73

А можно более конкретно ткнуть не в исходники, а в туториал - буду благодарен!

А что ты хочешь узнать то? Там обычные Tuples + вывод типов. Т.е. (1,2,3) имеет тип Int*Int*Int, вот и всё.

Norgat ★★★★★ ()
Ответ на: комментарий от Norgat

А в чём макароны тогда? Хотя наверное, сначала нужно дочитать книжку про Хаскель - я как раз прочитал 2 страницы.

den73 ★★★★★ ()
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от den73

А в чём макароны тогда?

Макароны там внутри компилятора, а не в клиентском коде.

Norgat ★★★★★ ()
Ответ на: комментарий от Norgat

Остальное, лично для меня, не существенно. Т.е. если бы в языке были только списки, но с поддержкой тех двух фич, что я описал выше, то для меня никакой разницы не было бы вообще.

Пожалуйста, научись писать, поскольку тебя читают люди. В питоне списки поддерживают «распаковку в переменные» => для тебя нет разницы, есть кортежи, или нет в питоне.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Virtuos86

Ну похоже, что из кортежей выпадает такая отдельная часть, как распаковка в переменные. Которая, впрочем, для имитации кортежей структкрами вряд ли вообще нужна - ведь можно просто записать структуру в переменную и писать переменная.поле-кортежа.

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

den73 ★★★★★ ()

В с++ tuple имеет операции !=,==, <, >,<=,>=

Представь у тебя есть список(list, vector, да любая коллекция списка) состоящая из структур, в структурах есть множество полей, возможно разных типов (например Фамилия, Имя, id депертамента работника). А ты хочешь отсоратировать список сначала по id департамента (int), потом по фамилии (string), потом по имени(string). Как ты это сделаешь?

А с std::sort, лямбдами и tuple,std::tie вся сортировка занимает одну срочку.

Dudraug ★★★★★ ()

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

Dudraug ★★★★★ ()
Ответ на: комментарий от Virtuos86

Пожалуйста, научись писать, поскольку тебя читают люди. В питоне списки поддерживают «распаковку в переменные» => для тебя нет разницы, есть кортежи, или нет в питоне.

И что ты мне хочешь доказать то? Что в питоне есть такая фича или что мне пофиг, что распаковывать - кортеж или список? И то и то я и без тебя знаю.

Norgat ★★★★★ ()

Сейчас копаюсь в потрохах SBCL и вижу, насколько они усложняют вывод типов и систему типов.

SBCL это вроде компилятор Common Lisp-а. В Common Lisp-е нет типов. Откуда тогда их вывод? Ты ничего не перепутал?

anonymous ()
Ответ на: комментарий от Dudraug

Мне нужно избавиться от как можно большего количества всякого мусора, чтобы язык вышел звонким, как монета. Соответственно, я пытаюсь понять, как избавиться от кортежей. В общем на данный момент я понял так, что избавиться от кортежей нельзя (т.к. они есть в лиспе, с которым нужен интерфейс), но можно объявить их deprecated и не поддерживать для них типизации, сказав: если вам нужен кортеж, то вам не нужен кортеж. Пользуйтесь структурами (обычно я всегда ненавижу тех, кто так пишет).

den73 ★★★★★ ()
Ответ на: комментарий от Dudraug

В лиспе есть тип t, который объемлет всё, поэтому этой проблемы нет (правда, за счёт этого лисп медленнее). Отвечаю на следующий вопрос: в лиспе есть типизированные указатели, поэтому цена не очень велика. Реальная цена состоит в том, что тип любого объекта известен в runtime, даже если на него указывает void*. Целое число содержит несколько фиксированных бит (тег типа) и доступный диапазон целых чисел получается меньше, чем в Си. Правда, в лиспе есть bignum-ы неограниченной точности, и при переполнении fixnum превращается в bignum .

den73 ★★★★★ ()
Последнее исправление: den73 (всего исправлений: 2)
Ответ на: комментарий от den73

Ну т.е. sequence - это кортеж? Так это ж не кортеж.

Каждый элемент sequence может быть как атомом, так и sequence'ом. Ежели этого мало, используй object.

quickquest ★★★★★ ()
Ответ на: комментарий от quickquest

Ну ладно, пусть будет. Но если у людей такие странные воззрения, то вряд ли их воззрения на кортеж имеют большое культурное значение.

den73 ★★★★★ ()
Ответ на: комментарий от den73

Кортежи нужны прежде всего для функционального подхода. Посмотри как часто и для чего они юзаются в функциональных языках типа Хаскель(по которому ты читаешь и не как не дочитаешь книжку) или OCaml.

Aswed ★★★★★ ()
Ответ на: комментарий от den73

Конкретно, в Питоне кортежи засунуты много где под капотом. Профит от них тот, что а) это гетерогенная структура данных (последовательный набор экземпляров любых типов); б) это константный тип данных (размер известен при определении).

Паттерн-матчинг действительно не привязан к какому-то конкретному типу данных.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от den73

если вам нужен кортеж, то вам не нужен кортеж

Так и чем твой язык лучше остальных? Возможно я чего-то не догоняю, но языков с локаничным синтаксисом и так хватает. Мне кажется, что сейчас восстрабованы выскоуровневые языки. Где можно простым кодом выражать сложные вещи, а не наоборот. Кому это не надо они останутся на си и си++.

Dudraug ★★★★★ ()
Ответ на: комментарий от Dudraug

Плюсую этого оратора. Си, паскаль и фортран уже существуют.

Aswed ★★★★★ ()
Ответ на: комментарий от den73

А где хеш-таблицы?

Есть мнение, что хэш-таблица должна быть частью стандартной либы, а не языка. Что позволит кастомизировать ее на лету, ну или вообще подменять типом с тем же концептом (и/или интерфейсом) как в с++.

Есть конечно языки где они часть языка, тот же ruby, что делает его довольно удобным и лаконичным для некоторых задач. Но один фиг, это очень спорно.

Где числа с плавающей точкой?

На самом деле тоже спорно, что они нужны. Не на всех аппаратных платформах она есть=)

Dudraug ★★★★★ ()
Ответ на: комментарий от den73

Единственное неудобство - это то, что тип структуры нужно объявлять. Но в этом можно видеть плюс, т.к. объявление структуры заставляет дать вещам имена и тем самым сделать программу более явной и понятной.

Проще возвращать гетерогенный список. А имена...

(defstruct quotient-remainder (quotient remainder))
floor : number &optional divisor => quotient-remainder

(let ((q (quotient-remainder-quotient (floor 3 2)))) ...)
понятности, ро-моему, убавилось.

Мне нужно избавиться от как можно большего количества всякого мусора, чтобы язык вышел звонким, как монета.

Если кортежей, в смысле multiple-values, то без проблем. можно и в функцию всегда передавать только одно значение. как в Хаскеле. Мощность языка не уменьшится.

monk ★★★★★ ()
Ответ на: комментарий от den73

не поддерживать для них типизации, сказав: если вам нужен кортеж, то вам не нужен кортеж

А гетерогенные списки будут? В смысле, типизация для них?

monk ★★★★★ ()
Ответ на: комментарий от den73

Эээ, при чем тут типы, при чем тут рефлексия. Я описал совсем другую задачу, которая никак не связана с этим. Или это ты не мне отвечал?

Dudraug ★★★★★ ()
Ответ на: комментарий от monk

Этот ваш лишп вообще читать невозможно

опр класс quotient-remainder () quotient reminder кно
декл функ floor (Число -- число, делитель = 1) -- quotient-reminder кнд

пусть q = floor(3, 2).quotient
Али плохо?

Проблема в лиспе в том, что повторяется слово quotient-reminder, а оно не нужно. Здесь вполне себе сработает вывод типов (и в лиспе он тоже сработает, но нет точки).

Список возвращать плохо из-за накладных расходов на сам список. Тогда уж массив. Но ничто не мешает просто вернуть массив, не называя его отдельным словом «кортеж».

den73 ★★★★★ ()
Последнее исправление: den73 (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.