Кортежи в языках программирования
От: NeoCode  
Дата: 24.10.12 09:34
Оценка: 1 (1)
Пытаюсь построить идеальную модель кортежей в некотором языке программирования.
Кортеж — это просто некоторая группа объектов (переменных, констант), не имеющая собственного типа, а существующая на этапе компиляции просто для удобства.
Записывается просто как список объектов в круглых скобках через запятую.

Такие варианты использования выглядят наиболее логично и красиво:

1. возврат нескольких значений из функции
(int,char,float) Foo()
{
  return (100,'a',3.14);
}


2. групповые операции
(i,j,k) = (1,2,3);


3. множественные операции
(i,j,k) = 100;
myobj.(i, c, f) = (100, 'q', 0.25);
sum += (i, j, k);


4. групповая и множественная индексация массивов (раскрытие массива в кортеж)
arr[2,4,8] = (10, 20, 30);
arr[10,20,30] = 0;
arr[indexes[0..size-1]] ++;


На простых примерах вроде все хорошо, но дальше начинаются противоречия и ужасы.
— поведение таких групп внутри сложных выражений ?
— простая, понятная и правильная логика обработки операций над двумя и более кортежами разных размеров ?
— передача кортежей в функции; по аналогии с возвращаемыми значениями, список аргументов функции тоже кортеж, но если возможен например инкремент сразу трех переменных, то что делать если программист хочет вызвать функцию сразу для трех переменных?
Foo((i,j,k)); //???
— соответственно, получение множественного возврата из обычных функций, в которые передали кортеж (по аналогии с операциями!)
(d1,d3,d3,d4) = sin(0.2, 0.4, 0.6, 0.8); // double sin(double x)
— ну и если рассматривать наложение ситуаций множественного возврата и множественных аргументов, то вообще бред получается.

Посмотрел в Питоне, там это просто структура данных. В Nemerle немного ближе (есть "раскрытие" кортежа в группу переменных) но "множестенных" операций и прочих наворотов нет.
Интересно было бы посмотреть, существует ли что-то похожее на эти идеи в других языках?
Re: Кортежи в языках программирования
От: RomikT Германия  
Дата: 24.10.12 10:08
Оценка:
Здравствуйте, NeoCode, Вы писали:

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


Посмотрите на HList в Scala, это в некотором роде расширение идеи кортежей.
Re: Кортежи в языках программирования
От: AlexRK  
Дата: 24.10.12 11:05
Оценка: +2
Здравствуйте, NeoCode, Вы писали:

NC>3. множественные операции


Я правильно понял, что

NC>
(i,j,k) = 100;

- присваивание каждому элементу значения 100?

NC>myobj.(i, c, f) = (100, 'q', 0.25);

- присваивание свойствам i, c, f значений 100, 'q' и 0.25 соответственно?

NC>sum += (i, j, k);


Добавление к sum суммы всех элементов кортежа?

ИМХО, все три действия сильно неинтуитивны.


NC>4. групповая и множественная индексация массивов (раскрытие массива в кортеж)

NC>arr[indexes[0..size-1]] ++;[/code]

Вот это тоже не понял.


NC>- поведение таких групп внутри сложных выражений ?


Либо запретить, либо вводить наименования полей (возможно, опциональные).

NC>- простая, понятная и правильная логика обработки операций над двумя и более кортежами разных размеров ?


Например, какие операции?

NC>- передача кортежей в функции; по аналогии с возвращаемыми значениями, список аргументов функции тоже кортеж, но если возможен например инкремент сразу трех переменных, то что делать если программист хочет вызвать функцию сразу для трех переменных?

NC>Foo((i,j,k)); //???

Я думал над этим вопросом, пришел к выводу, что вообще эта идея — аргументы функции есть кортеж — плохая. Но почему, уже не помню.
В данном конкретном случае, вероятно, должна быть просто ошибка компиляции (двусмысленность).

NC>- соответственно, получение множественного возврата из обычных функций, в которые передали кортеж (по аналогии с операциями!)

NC>(d1,d3,d3,d4) = sin(0.2, 0.4, 0.6, 0.8); // double sin(double x)
NC>- ну и если рассматривать наложение ситуаций множественного возврата и множественных аргументов, то вообще бред получается.

Я бы эту путаницу — с произвольным количеством аргументов вместо одного — просто запретил. Читаемость кода, ИМХО, будет очень низкая.

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


По-моему, в нормальном, продуманном, последовательном виде — нет нигде. Разной степени кривизны много где.
Re[2]: Кортежи в языках программирования
От: NeoCode  
Дата: 24.10.12 11:31
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Я правильно понял, что

NC>>
(i,j,k) = 100;
ARK>- присваивание каждому элементу значения 100?
NC>>myobj.(i, c, f) = (100, 'q', 0.25);
ARK>- присваивание свойствам i, c, f значений 100, 'q' и 0.25 соответственно?
NC>>sum += (i, j, k);

ARK>Добавление к sum суммы всех элементов кортежа?

Да, все верно.

ARK>ИМХО, все три действия сильно неинтуитивны.

Почему?

NC>>4. групповая и множественная индексация массивов (раскрытие массива в кортеж)

NC>>arr[indexes[0..size-1]] ++;[/code]

ARK>Вот это тоже не понял.

Ну это я наверное не написал подробно... массив, проиндексированный несколькими индексами (кортежем) раскрывается в кортеж.
 (x,y,z) = arr[0,1,2];
(x,y,z) = arr[0..2];


NC>>- поведение таких групп внутри сложных выражений ?

ARK>Либо запретить, либо вводить наименования полей (возможно, опциональные).

А подробнее про наименования полей?

NC>>- простая, понятная и правильная логика обработки операций над двумя и более кортежами разных размеров ?

ARK>Например, какие операции?
(x,y,z)  = (i,j);
(x,y,z) += (i,j);
(x,y)  = (i,j,k);
(x,y) += (i,j,k);

что делать в этих случаях — ругаться? цикл по наименьшему размеру? цикл по наибольшему размеру с "переполнением" (индекс каждого кортежа делится по модулю на длину кортежа) ? цикл по наибольшему размеру с "насыщением" (индекс каждого кортежа при достижении максимума остается на максимуме)? декартово произведение (двойной цикл по обоим кортежам)?)

NC>>- передача кортежей в функции; по аналогии с возвращаемыми значениями, список аргументов функции тоже кортеж, но если возможен например инкремент сразу трех переменных, то что делать если программист хочет вызвать функцию сразу для трех переменных?

NC>>Foo((i,j,k)); //???
ARK>Я думал над этим вопросом, пришел к выводу, что вообще эта идея — аргументы функции есть кортеж — плохая. Но почему, уже не помню.
ARK>В данном конкретном случае, вероятно, должна быть просто ошибка компиляции (двусмысленность).

Если еще кортежи сделать именованными (хотя-бы через аналог #define) то возникнет еще одно некрасивое место:
define (1,2,3) FOO;
define(4,5) BAR;
//void Func(int a1,int a2,int a3,int a4,int a5,int a6,int a7)
Func(100,FOO,BAR,200); // если рассматривтаь это как конкатенацию кортежей, некрасиво то что не видно сколько реально аргументов и какие значения в них ложатся; а если рассматривать как мультвызов - то бред, сколько раз вызывать функцию
Re[3]: Кортежи в языках программирования
От: AlexRK  
Дата: 24.10.12 12:43
Оценка:
Здравствуйте, NeoCode, Вы писали:

ARK>>ИМХО, все три действия сильно неинтуитивны.

NC>Почему?

Ну вот это — "myobj.(i, c, f) = (100, 'q', 0.25);" — вообще со стандартной статической типизацией несовместимо, плюс мало читаемо.
myobj.t = u; — чего здесь происходит, если t и u — кортежи? Совершенно непонятно.

(i,j,k) = 100; можно записать как и (i,j,k) = (100,100,100);
Опять лишняя путаница.

sum += (i, j, k);
В принципе более-менее, но это скорее для массивов должно подходить, чем для кортежей. Кортежи могут ведь содержать поля разных типов, зачем для них такой специфичный функционал?

Вообще, ИМХО, кортежи не стоило бы рассматривать как последовательности однотипных данных.

NC>Ну это я наверное не написал подробно... массив, проиндексированный несколькими индексами (кортежем) раскрывается в кортеж.

NC>
 (x,y,z) = arr[0,1,2];
NC>(x,y,z) = arr[0..2];


А, понятно.
Фиг знает, лично мне не нравится смешивание массивов и кортежей — это же разные вещи в общем случае.

NC>>>- поведение таких групп внутри сложных выражений ?

ARK>>Либо запретить, либо вводить наименования полей (возможно, опциональные).
NC>А подробнее про наименования полей?

Ну чего-то типа:
var tuple = (Name => "Sam", Age => 30, Sex => Sexes.Male);

var expr = 10 + tuple.Age;


NC>>>- простая, понятная и правильная логика обработки операций над двумя и более кортежами разных размеров ?

ARK>>Например, какие операции?
NC>
(x,y,z)  = (i,j);
NC>(x,y,z) += (i,j);
NC>(x,y)  = (i,j,k);
NC>(x,y) += (i,j,k);

NC>что делать в этих случаях — ругаться? цикл по наименьшему размеру? цикл по наибольшему размеру с "переполнением" (индекс каждого кортежа делится по модулю на длину кортежа) ? цикл по наибольшему размеру с "насыщением" (индекс каждого кортежа при достижении максимума остается на максимуме)? декартово произведение (двойной цикл по обоим кортежам)?)

Нда, жесть. Представьте, что в процессе отладки программы марсохода "Спирит", вылетающего завтра на Марс, вы встретите подобные конструкции. Я думаю, это будет не особо весело.
Мое мнение — должна быть ошибка компиляции.
А если фигакнуть еще вложенных кортежей, то вообще все круто будет: ((a, b), ((c, d), e, f), g) = (100, (21, 'q'))

NC>Если еще кортежи сделать именованными (хотя-бы через аналог #define) то возникнет еще одно некрасивое место:

NC>
define (1,2,3) FOO;
NC>define(4,5) BAR;
NC>//void Func(int a1,int a2,int a3,int a4,int a5,int a6,int a7)
NC>Func(100,FOO,BAR,200); // если рассматривтаь это как конкатенацию кортежей, некрасиво то что не видно сколько реально аргументов и какие значения в них ложатся; а если рассматривать как мультвызов - то бред, сколько раз вызывать функцию


Ну, как мультивызов рассматривать — это просто контр-интуитивно, по крайней мере для среднестатистического программиста. Может быть, только если человека тренировать на таких языках с мультивызовами, то ему это будет очевидно.
Остается конкатенация, но это тоже не особо понятно.
В общем, я бы операцию распаковки кортежа не стал совмещать с операцией вызова функции.
Re: Кортежи в языках программирования
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 24.10.12 16:10
Оценка:
Здравствуйте, NeoCode, Вы писали:

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


Це ж обычный product type, больше известный как tuple. Есть во всех основных функциональных языках, и на первых страницах книжек по теории типов.
Re[2]: Кортежи в языках программирования
От: NeoCode  
Дата: 24.10.12 17:02
Оценка: +1
Здравствуйте, D. Mon, Вы писали:

DM>Це ж обычный product type, больше известный как tuple. Есть во всех основных функциональных языках, и на первых страницах книжек по теории типов.


tuple обычно и переводится как кортеж.
А в функциональных языках что есть множественные операции по типу тех, которые я привел в качестве примера?
Re[3]: Кортежи в языках программирования
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 24.10.12 17:31
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>А в функциональных языках что есть множественные операции по типу тех, которые я привел в качестве примера?


Только некоторые, вроде множественного присваивания, ну и передача туда-сюда в функции, само собой, т.к. это обычный тип получается. Операции с массивами можно реализовать самому при желании. И кортеж там это не "группа объектов (переменных, констант), не имеющая собственного типа", тип там автоматически генерится из типов входящих в кортеж значений. Так, кортеж (1, 2.0, "three") в хаскеле может иметь тип (Int, Float, String), в окамле — int * float * string, а в каком-нибудь D — Tuple!(int, float, string).
Re: Кортежи в языках программирования
От: batu Украина  
Дата: 24.10.12 18:00
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>- поведение таких групп внутри сложных выражений ?

NC>- простая, понятная и правильная логика обработки операций над двумя и более кортежами разных размеров ?
Согласен с AlexRK. Проблема в неопределенности операций. Обычно это функция над двумя параметрами (хотя я считаю что операции надо определять иначе.). Если с суммой еще можно сынтуичить, то с вычитанием и делением возникает проблема с порядком выполнения. Это же касается и логических сравнения. Если два элемента то понятно. А если несколько, то что с чем и в каком порядке сравнивать? И как поступать если часть равны, а часть нет. Появляются варианты.
Я у себя определил изначально операции над группами. Т.е. сумма понятно, вычитание из последнего вычитается предпоследний и т.д.. Логических операций и опреаций сравнения пришлось определять несколько. AllEqv (все равны) и некоторые не равны.. Заметь что Не все равны это не одно и тоже что некоторые не равны Ну, а дальше сам додумаешь. Удачи!
Re: Кортежи в языках программирования
От: os24ever
Дата: 24.10.12 18:05
Оценка: :)
NC>Интересно было бы посмотреть, существует ли что-то похожее на эти идеи в других языках?

Если в языке есть дерево типов данных, в корне которого "Any" и затем "AnyVal" и "AnyRef", то это просто массив элементов "AnyRef".
То есть, динамический массив чего угодно. А все действия с ним — функции.

То есть, можно было бы написать просто:

Call ArraySlice Old_tuple, i, j, New_tuple
Call ArraySort New_tuple

Но обычно в язык насыпают 100500 кг синтаксического сахара вроде:

new_tuple = old_tuple[i..j].sort()

На самом деле, никакой разницы нет.
Re[2]: Кортежи в языках программирования
От: NeoCode  
Дата: 25.10.12 06:57
Оценка:
Здравствуйте, os24ever, Вы писали:

O>Если в языке есть дерево типов данных, в корне которого "Any" и затем "AnyVal" и "AnyRef", то это просто массив элементов "AnyRef".

O>То есть, динамический массив чего угодно. А все действия с ним — функции.
O>То есть, можно было бы написать просто:

O>
O>Call ArraySlice Old_tuple, i, j, New_tuple
O>Call ArraySort New_tuple
O>

O>Но обычно в язык насыпают 100500 кг синтаксического сахара вроде:

O>
O>new_tuple = old_tuple[i..j].sort()
O>

O>На самом деле, никакой разницы нет.

Я предполагаю что все эти кортежи на этапе компиляции будут раскрываться в последовательности одиночных операций, то есть никакие это не массивы. Например,
(x, y)++;

будет превращен в
x++; y++;

а
(x, "Hello world")++;

приведет к ошибке компиляции. То есть я здесь понимаю под tuple не еще один тип данных (как массив, список, ...) а некое языковое средство для синтаксической группировки объектов.
Например в go есть операция группового присваивания
i, j = 100,200

никаких массивов тут нет. Интересно, как далеко можно расширить такие групповые операции?
Re[2]: Кортежи в языках программирования
От: NeoCode  
Дата: 25.10.12 06:58
Оценка:
Здравствуйте, batu, Вы писали:

B>Я у себя определил изначально операции над группами. Т.е. сумма понятно, вычитание из последнего вычитается предпоследний и т.д.. Логических операций и опреаций сравнения пришлось определять несколько. AllEqv (все равны) и некоторые не равны.. Заметь что Не все равны это не одно и тоже что некоторые не равны Ну, а дальше сам додумаешь. Удачи!


Можно подробнее?
Re[3]: Кортежи в языках программирования
От: Sinix  
Дата: 25.10.12 08:06
Оценка: +1
Здравствуйте, NeoCode, Вы писали:


NC>Я предполагаю что все эти кортежи на этапе компиляции будут раскрываться в последовательности одиночных операций, то есть никакие это не массивы. Например,

(x, y)++;


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

В плюсе — возможность одновременно выполнять операции над несколькими переменными, всё остальное достигается обычным синтаксисом.

В минусе (навскидку):

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

— этот синтаксис нужен только для очень редких случаев — для операций над статическим списком переменных/значений — но затрагивает весь язык.

— этот синтаксис провоцирует плохой стиль кодирования, когда изменение состояния размазано по нескольким переменным, или в одной операции производятся семантически разные вещи.

Пример раз:
(checksPassed, personAge)++;

Пример два:
(a,b,c) = InitVars();
выглядит красивее, чем
int a,b,c;
InitVars(out a, out b, out c);
но оно скрывает одну проблему: ужасен не вызов метода, ужасен сам метод, который совершает операции над тремя логически несвязанными объектами.
Re[3]: Кортежи в языках программирования
От: batu Украина  
Дата: 25.10.12 08:09
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>Здравствуйте, batu, Вы писали:


B>>Я у себя определил изначально операции над группами. Т.е. сумма понятно, вычитание из последнего вычитается предпоследний и т.д.. Логических операций и опреаций сравнения пришлось определять несколько. AllEqv (все равны) и некоторые не равны.. Заметь что Не все равны это не одно и тоже что некоторые не равны Ну, а дальше сам додумаешь. Удачи!


NC>Можно подробнее?

Что именно подробней? Операция вычитания группы может быть определена по разному.. Из первого вычитается второй, из результата вычитается третий и т.д.. А можно и с последнего начать.. Тоже самое и для остальных операций.. Придумываешь и реализуешь. С суммой и умножением просто потому как там вариантов нет. Остальные операции крути как хочешь. В смысле как считаешь разумным.
Re[4]: Кортежи в языках программирования
От: NeoCode  
Дата: 25.10.12 08:23
Оценка:
Здравствуйте, batu, Вы писали:

B>Что именно подробней? Операция вычитания группы может быть определена по разному.. Из первого вычитается второй, из результата вычитается третий и т.д.. А можно и с последнего начать.. Тоже самое и для остальных операций.. Придумываешь и реализуешь. С суммой и умножением просто потому как там вариантов нет. Остальные операции крути как хочешь. В смысле как считаешь разумным.


Элементы группы не взаимодействуют между собой при групповых операциях, имеется в виду только взаимодействие i-того элемента группы и другого операнда.
x -= (1,2,3); // x-=1; x-=2; x-=3;
(x,y,z) -= 10; // x-=10; y-=10; z-=10;
(x,y,z) -= (1,2,3); // x-=1; y-=2; z-=3;
Re[5]: Кортежи в языках программирования
От: maykie Россия  
Дата: 25.10.12 09:11
Оценка:
Здравствуйте, NeoCode, Вы писали:

NC>Здравствуйте, batu, Вы писали:


B>>Что именно подробней? Операция вычитания группы может быть определена по разному.. Из первого вычитается второй, из результата вычитается третий и т.д.. А можно и с последнего начать.. Тоже самое и для остальных операций.. Придумываешь и реализуешь. С суммой и умножением просто потому как там вариантов нет. Остальные операции крути как хочешь. В смысле как считаешь разумным.


NC>Элементы группы не взаимодействуют между собой при групповых операциях, имеется в виду только взаимодействие i-того элемента группы и другого операнда.

NC>
x -= (1,2,3); // x-=1; x-=2; x-=3;
NC>(x,y,z) -= 10; // x-=10; y-=10; z-=10;
NC>(x,y,z) -= (1,2,3); // x-=1; y-=2; z-=3;


А почему третий пример раскрывается так, а не x -= (1,2,3);y -= (1,2,3);z -= (1,2,3); ?
Re[6]: Кортежи в языках программирования
От: NeoCode  
Дата: 25.10.12 09:19
Оценка:
Здравствуйте, maykie, Вы писали:

NC>>
x -= (1,2,3); // x-=1; x-=2; x-=3;
NC>>(x,y,z) -= 10; // x-=10; y-=10; z-=10;
NC>>(x,y,z) -= (1,2,3); // x-=1; y-=2; z-=3;


M>А почему третий пример раскрывается так, а не x -= (1,2,3);y -= (1,2,3);z -= (1,2,3); ?


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

А вот если захотеть, чтобы работали первые два примера — начинаются проблемы в более сложных случаях, о чем и тема
Re[4]: Кортежи в языках программирования
От: hardcase Пират http://nemerle.org
Дата: 25.10.12 09:31
Оценка: 20 (1) +1
Здравствуйте, Sinix, Вы писали:


S>
S>int a,b,c;
S>InitVars(out a, out b, out c);
S>
но оно скрывает одну проблему: ужасен не вызов метода, ужасен сам метод, который совершает операции над тремя логически несвязанными объектами.


На самом деле элементы кортежа обычно логически связаны — не просто же так их в кортеж-то объединили. В примере с методом, который возвращает кортеж, вместо него вполне мог быть как-то специальный тип данных, но задача настолько мелкая и локальная, что для этого объявлять специальный тип данных как-то непрактично (overkill).

А в остальном, да я согласен. Замечу, что кортежи имеют смысл лишь в языках, поддерживающих сопоставление с образцом — декомпозиция кортежа это частный случай такой операции, в противном случае кортежи вырождаются до примитивных контейнеров безымянных данных.
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Кортежи в языках программирования
От: vl690001x Россия  
Дата: 25.10.12 10:15
Оценка:
Я только недавно узнал что в C# есть кортежи, но активно их использую, чтобы не создавать новые типы.
Например, у меня есть метод, который возвращает строку — содержимое некого url. Также, если сервер недоступен, надо как-то передать эту информацию из метода. Можно конечно вернуть null, и возможно это проще, но правильней было бы создать класс:
class ReturnedValue
{
  public bool HostAvailable;
  public string HostValue;
}


и возвращать объект этого класса.

Только аналогичных методов может быть много, поэтому для каждого создавать класс слишком утомительно, можно просто вернуть кортеж:
new Tuple<bool,string>(true, "value");


или:
new Tuple<bool,string>(false,null);


и считывать информацию из кортежа так:
if(tuple.Item1)
{
  Console.WriteLine(tuple.Item2);
}
else
{
 Console.WriteLine("Сервер недоступен");
}
)
Re[2]: Кортежи в языках программирования
От: hardcase Пират http://nemerle.org
Дата: 25.10.12 10:27
Оценка: +2
Здравствуйте, vl690001x, Вы писали:

V>Только аналогичных методов может быть много, поэтому для каждого создавать класс слишком утомительно, можно просто вернуть кортеж:


V>new Tuple<bool,string>(true, "value");


V>или:


V>new Tuple<bool,string>(false,null);


1) Кортежи в C# можно и нужно изготавливать так:
Tuple.Create(true, "value");


2) Для вашей задачи есть отличный паттерн "монада Maybe". В ML-подобных языках для ее поддержки существует обобщенный тип option[T], который нетрудно воспроизвести в .NET (как обобщение типа Nullable<T>, только за исключением ограничение на value-типы).
/* иЗвиНите зА неРовнЫй поЧерК */
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.