Функциональное метапрограммирование
От: AlexCab LinkedIn
Дата: 22.02.12 15:25
Оценка:
Язык(среду/код) можно представить в виде направленного графа, узлы которого это набор определённых термов(единиц языка) который использует программист для написания программы и/или новых термов. Наверху графа находятся самые сложные термы состоящие из множества других, внизу примитивные(например операторы и т.п. целевой платформы). Дуги графа это ссылки указывающие на используемые термы.

(Так можно представить практически любой язык, в Си например узлами будут функции/структуры и операторы/примитивные типы(нижний уровень).)
Каждый терм в мета языке фактически представляет собой правило описывающие конструкцию(из термов на которые ссылается данный) на которую будет заменён терм после "вызова". Компилирование мета кода это преобразование всех термов в примитивные.
Например программист написал код:
a1 b2 b4 с3 d2 c2

Правила для использованных не примитивных термов:
a1 => b2 b1
b2 => c1
b4 => c4 d3
с3 => d2 d3
c2 => d2 d1
b1 => c1
c1 => d1
c4 => d3
В результате получится:
d1 d1 d1 d3 d3 d2 d3 d2 d2 d1

Представление компилирования в виде графа:

Абстрактно можно представить что граф, во время компиляции, как бы "разрастается" сверху вниз.

Скажите я правильно понял концепцию?
Спасибо.
Между тем,что я думаю,тем,что я хочу сказать,тем,что я,как мне кажется,говорю,и тем,что вы хотите услышать,тем,что как вам кажется,вы слышите,тем,что вы понимаете,стоит десять вариантов возникновения непонимания.Но всё-таки давайте попробуем...(Э.Уэллс)
Re: Функциональное метапрограммирование
От: hardcase Пират http://nemerle.org
Дата: 22.02.12 15:48
Оценка:
Здравствуйте, AlexCab, Вы писали:

AC>Скажите я правильно понял концепцию?


О какой концепции речь?
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: Функциональное метапрограммирование
От: AlexCab LinkedIn
Дата: 22.02.12 16:04
Оценка:
Здравствуйте, hardcase, Вы писали:
H>О какой концепции речь?

О совмещении функционального и метапрограммирования.
Между тем,что я думаю,тем,что я хочу сказать,тем,что я,как мне кажется,говорю,и тем,что вы хотите услышать,тем,что как вам кажется,вы слышите,тем,что вы понимаете,стоит десять вариантов возникновения непонимания.Но всё-таки давайте попробуем...(Э.Уэллс)
Re: Функциональное метапрограммирование
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 22.02.12 16:16
Оценка: 1 (1)
AC>Скажите я правильно понял концепцию?

в первом приближении — да.

но такие преобразования не умеют напрямую(то, что через ad-hoc полиморфизм описывается одним правилом, при таком описании может потребовать увеличение кол-ва уже имещихся правил в k-раз) описывать ad-hoc полиморфизм (оно же контекстно-зависимые термы)
Re[3]: Функциональное метапрограммирование
От: x-code  
Дата: 22.02.12 18:40
Оценка:
Здравствуйте, AlexCab, Вы писали:

H>>О какой концепции речь?

AC>О совмещении функционального и метапрограммирования.

Ничего не понял, как вы собираетесь совмещать и зачем так абстрактно? Все же гораздо интереснее говорить о конкретных вещах, встречающихся в реальном программировании, а не об абстрактных "a1", "b2" etc.

Могу сказать, что метапрограммирование проще всего воспринимать так. Есть несколько этапов компиляции. На первом этапе программа из исходного текста превращается в список токенов (лексический анализ), на втором — в синтаксическое дерево (AST). Это дерево ближе всего к тому, как программист представляет программу. Если у вас есть класс, в нем метод, в методе блок (например if), в блоке аргумент условия, то это и есть дерево, где корень — сама программа, дальше — пространства имен, классы, функции, блоки, выражения, части выражений и в конце концов листья дерева — переменные, константы.

Можно предположить, что на разных этапах с представлением программы можно что-то делать Некие "действия, определенные пользователем". Так, препроцессор Си обрабатывает программу как последовательность токенов, а более продвинутые системы метапрограммирования — на этапе AST. Соответственно, метапрограммирование — это написание кода, реализующего эти действия.

В простейшем случае такими действиями будет просто подстановка фрагмента представления программы вместо некоторого аргумента. Например, в некоторой системе метапрограммирования есть "шаблоны" — по сути специальные параметризированные заготовки кода.

В С++ система шаблонов построена чисто на подстановках, потому она такая монструозная. Если придумать другую систему метапрограммирования, в которой кроме подстановок будут разрешены другие — "активные" действия, определенные пользователем — то получим полноценные "плагины к компилятору", пользовательский код, который будет выполняться прямо внутри компилятора на различных этапах компиляции.

Ну а этот код может быть написан в любой парадигме — на ассемблере, в процедурном стиле, в фуникцональном или объектно-ориентированном, или на смеси всех стилей вместе взятых, или еще каким-то образом, неизвестным науке. Это вопрос того, какой интерфейс предоставляет компилятор для доступа к самому себе. Это может быть какой-нибудь скриптовый язык типа javascript, или тот же самый язык, на котором написана основная программа — не важно, главное что если такая возможность есть, то парадигма метапрограммирования реализована полностью.
Re[2]: Функциональное метапрограммирование
От: x-code  
Дата: 22.02.12 18:44
Оценка:
Здравствуйте, DarkGray, Вы писали:

AC>>Скажите я правильно понял концепцию?

DG>в первом приближении — да.

DG>но такие преобразования не умеют напрямую(то, что через ad-hoc полиморфизм описывается одним правилом, при таком описании может потребовать увеличение кол-ва уже имещихся правил в k-раз) описывать ad-hoc полиморфизм (оно же контекстно-зависимые термы)


Расскажите что такое ad-hoc полиморфизм (и в чем разница с параметрическим) и контекстно-зависимые термы? На википедии скомканная пара абзацев, да к тому же про haskell которого я не знаю
Re: Функциональное метапрограммирование
От: batu Украина  
Дата: 22.02.12 19:19
Оценка:
Здравствуйте, AlexCab, Вы писали:

AC>Язык(среду/код) можно представить в виде направленного графа, узлы которого это набор определённых термов(единиц языка) который использует программист для написания программы и/или новых термов. Наверху графа находятся самые сложные термы состоящие из множества других, внизу примитивные(например операторы и т.п. целевой платформы). Дуги графа это ссылки указывающие на используемые термы.

AC>
AC>(Так можно представить практически любой язык, в Си например узлами будут функции/структуры и операторы/примитивные типы(нижний уровень).)
Представить можно в виде графа, в виде сети петри, в виде пятерки.. Дело ж не в том.. Ради чего такое представление и какие выводы из этого можно сделать.. Т.е. какой смысл в таком представлении. Что это нам дает?
Re[4]: Функциональное метапрограммирование
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 22.02.12 19:30
Оценка:
XC> Ничего не понял, как вы собираетесь совмещать и зачем так абстрактно?

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

желательно в голове иметь оба представление: как это делается, и что при этом происходит. Формулировка AlexCab чуть более ценная, потому что меньшее кол-во людей умеет её формулировать и оперировать ей.

XC>Могу сказать, что метапрограммирование проще всего воспринимать так.


тогда проще сказать, что метапрограммирование — это функция, которая берет на входе код и выдает на выходе другое код F:код -> код.
вид представления кода: текст, бинарник, ast и т.д. — это уже больше задача удобства.


XC> Расскажите что такое ad-hoc полиморфизм (и в чем разница с параметрическим) и контекстно-зависимые термы?


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

вот это параметрический полиморфизм (Add определен через + с помощью одного варианта кода)
T Add<T>(T x1, T x2)
{
   return x1 + x2;
}


а вот это ad-hoc полиморфизм (Add определен разными способами в зависимости от типа)
int Add(int x1, int x2)
{
  return x1 + x2;
}
int[] Add(int[] x1, int[] x2)
{
   return x1.Concat(x2).ToArray();
}


контекстно-зависимые термы:
var x = 5;
int var = 1;

в первом случае, var преобразуется в объявление переменной, во втором в название переменной.

Console.WriteLine(x * 3);
var x = 5;
Console.WriteLine(x * 3);

первая строка "Console.WriteLine(x * 3)" преобразуется в ошибку компиляции, что переменная x не используется,
ровно такая же третья строка преобразуется в несколько инструкций byte-кода
Re[2]: Функциональное метапрограммирование
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 22.02.12 19:39
Оценка:
B> Т.е. какой смысл в таком представлении. Что это нам дает?

если преобразование удалось представить в виде приведенного графа, то это дает возможность построить автомат, который будет транслировать код линейно за O(длина исходного кода) (или если есть ограничения по памяти, то почти линейно O(длина исходного кода * log длина исходного кода))
если такой граф построить не удалось, то стоимость транслирующего алгоритма будет выше линейной (и скорее всего выше, чем O(nlogn)).
Re[5]: Функциональное метапрограммирование
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.02.12 20:00
Оценка: +1
Здравствуйте, DarkGray, Вы писали:

DG>вот это параметрический полиморфизм (Add определен через + с помощью одного варианта кода)

DG>
DG>T Add<T>(T x1, T x2)
DG>{
DG>   return x1 + x2;
DG>}
DG>


Если бы компилилось на С#, было бы типичным образчиком ad-hoc полиморфизма. Здесь фактически задается имя Add для оператора сложения, который полиморфен именно в ad-hoc смысле, т.к. невозможно складывать значения обобщенным образом, не имея специальной информации о типе. Класть их в кортеж — можно. Складывать — увы. Об этом тебе должен был сказать компилятор.
Re[6]: Функциональное метапрограммирование
От: x-code  
Дата: 22.02.12 20:19
Оценка:
Здравствуйте, samius, Вы писали:

DG>>вот это параметрический полиморфизм (Add определен через + с помощью одного варианта кода)

DG>>
DG>>T Add<T>(T x1, T x2)
DG>>{
DG>>   return x1 + x2;
DG>>}
DG>>


S>Если бы компилилось на С#, было бы типичным образчиком ad-hoc полиморфизма. Здесь фактически задается имя Add для оператора сложения, который полиморфен именно в ad-hoc смысле, т.к. невозможно складывать значения обобщенным образом, не имея специальной информации о типе. Класть их в кортеж — можно. Складывать — увы. Об этом тебе должен был сказать компилятор.


Ну то есть параметрический полиморфизм — это когда нам действительно пофиг, что там за типы — как на этапе компиляции, так и на этапе выполнения. Например, вызываем метод базового типа, который никак не переопределен в дочерних типах.
А ad-hoc — когда на этапе компиляции нам пофиг, а на этапе выполнения — уже нет. Например — вызываем метод, который переопределен в каждом дочернем типе как-то по своему.
Я прав?
Re[6]: Функциональное метапрограммирование
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 22.02.12 20:57
Оценка:
S>Если бы компилилось на С#, было бы типичным образчиком ad-hoc полиморфизма. Здесь фактически задается имя Add для оператора сложения, который полиморфен именно в ad-hoc смысле, т.к. невозможно складывать значения обобщенным образом, не имея специальной информации о типе. Класть их в кортеж — можно. Складывать — увы. Об этом тебе должен был сказать компилятор.

про C# говорить сложно, потому что он не умеет использовать ad-hoc полиморфизм из параметрического полиморфизма

в следующем коде: Sum — параметрический полиморфизм, Add — ad-hoc полиморфизм, Add2 — можно трактовать и так, и так, в зависимости от того как делается деление по входу или по выходу.
template<typename T>
T Sum(typename std::vector<T>::iterator begin, typename std::vector<T>::iterator end)
{
    T t;
    for (typename std::vector<T>::const_iterator it = begin; it != end; ++it)
    {
      Add2(t, *it);
    }
    return t;
};

template<typename T>
void Add2(T& x, T value)
{
  x = Add(x, value);
}


bool Add(int x, int value)
{
    return  x + value;
}

bool Add(bool x, bool value)
{
    return x || value;
}


S> т.к. невозможно складывать значения обобщенным образом, не имея специальной информации о типе. Класть их в кортеж — можно.


по такому определению даже вектор не является параметрическим полиморфизмом, потому что при хранении типа в векторе требуется специальная информация от типа, как именно данный тип копируется, и соответственно компилятор должен был бы сказать "бла-бла, то что ты там утверждаешь".
Re[7]: Функциональное метапрограммирование
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.02.12 20:57
Оценка:
Здравствуйте, x-code, Вы писали:

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


DG>>>вот это параметрический полиморфизм (Add определен через + с помощью одного варианта кода)

DG>>>
DG>>>T Add<T>(T x1, T x2)
DG>>>{
DG>>>   return x1 + x2;
DG>>>}
DG>>>


S>>Если бы компилилось на С#, было бы типичным образчиком ad-hoc полиморфизма. Здесь фактически задается имя Add для оператора сложения, который полиморфен именно в ad-hoc смысле, т.к. невозможно складывать значения обобщенным образом, не имея специальной информации о типе. Класть их в кортеж — можно. Складывать — увы. Об этом тебе должен был сказать компилятор.


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

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

XC>А ad-hoc — когда на этапе компиляции нам пофиг, а на этапе выполнения — уже нет. Например — вызываем метод, который переопределен в каждом дочернем типе как-то по своему.

XC>Я прав?
Ad-hoc — это все, что связано со специальными знаниями о типе. Прежде всего — операторы, которые определены для множества типов. Например, складывать можем целые, плавающие, строки. Для каждого случая ищется специальный способ сложения. Вывод в консоль значения требует специального знания о том, как это значение преобразовать в строку. Перегрузка (overload) методов, операторов — типичный пример ad-hoc полиморфизма.

Отдельной категорией идет subtype полиморфизм. Прежде всего он родственен с параметрическим, потому как позволяет вызывать код единым образом для всех подтипов (но не позволяет для неродственных типов). Отдельный смысл у subtype полиморфизма в ООП программировании подразумевается в возможности переопределять (override) методы для подтипов. Это роднит его с ad-hoc полиморфизмом, т.к. позволяет указывать специальные методы для отдельных ветвей подтипов.

В жизни это все здорово перемешивается. Например, Dictionary<K,V> — вроде как пример параметрически полиморфного контейнера. Пока мы параметризуем его создание специальным объектом, который учит контейнер считать хэшкод и сравнивать элементы, — все впорядке. Однако, сам компарер — образец subtype полиморфизма. Если мы его не подадим, будет подан EqualityComparer<K>.Default, который зная о типе K может подсунуть специальный компарер для K. Это уже ad-hoc (причем времени выполнения, а не компиляции).
Re[3]: Функциональное метапрограммирование
От: batu Украина  
Дата: 22.02.12 21:06
Оценка:
Здравствуйте, DarkGray, Вы писали:

B>> Т.е. какой смысл в таком представлении. Что это нам дает?


DG>если преобразование удалось представить в виде приведенного графа, то это дает возможность построить автомат, который будет транслировать код линейно за O(длина исходного кода) (или если есть ограничения по памяти, то почти линейно O(длина исходного кода * log длина исходного кода))

DG>если такой граф построить не удалось, то стоимость транслирующего алгоритма будет выше линейной (и скорее всего выше, чем O(nlogn)).
Во первых какой такой "приведенный граф"? .
Во-вторых речь шла цитирую "Язык(среду/код) можно представить в виде направленного графа, узлы которого это набор определённых термов(единиц языка) который использует программист для написания программы и/или новых термов. Наверху графа находятся самые сложные термы состоящие из множества других, внизу примитивные(например операторы и т.п. целевой платформы). Дуги графа это ссылки указывающие на используемые термы". Вам не кажется что "представить преобразование" и "представить язык" это разные вещи?
В-третьих, совсем не очевидно если можно представить (и что представить язык или преобразования) в (я так и не понял какие такие особые свойства у данного графа) таком виде то компиляция будет линейна.
В-четвертых, я не усмотрел там рекурсии. И в языке и в преобразовании она обычно присутствует. Собственно, это именна та фишка которая позволяет генерировать довольно мощные языки из грамматики. Без рекурсивности в определения грамматик нам пришлось бы сложновато. Отсюда следует любопытная штука.. Что преобразование выглядит вроде простым, а реально там будет рекурсия в разборе.. а вместе с рекурсией возникает не линейность в разборе.. не со всякой рекурсией, конечно, но в общем случае возникает..
И в пятых. Язык сам по себе являющимся линейным.. в том смысле, что там одна буква следует за другой, может иметь иерархическое содержание которое влечет за собой рекурсию. Классический пример: "У попа была собака он ее любил, потом убил и закопал и надпись написал "у попа бывла собака он ее любил...". Или вызов рекурсивной функции..
И... хотя этого достаточно.. не хочется сюда вопросы философии лепить..
Re[7]: Функциональное метапрограммирование
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.02.12 21:08
Оценка:
Здравствуйте, DarkGray, Вы писали:


S>>Если бы компилилось на С#, было бы типичным образчиком ad-hoc полиморфизма. Здесь фактически задается имя Add для оператора сложения, который полиморфен именно в ad-hoc смысле, т.к. невозможно складывать значения обобщенным образом, не имея специальной информации о типе. Класть их в кортеж — можно. Складывать — увы. Об этом тебе должен был сказать компилятор.


DG>про C# говорить сложно, потому что он не умеет использовать ad-hoc полиморфизм из параметрического полиморфизма

Вот пример EqualityComparer<T>.Default

DG>в следующем коде: Sum — параметрический полиморфизм, Add — ad-hoc полиморфизм, Add2 — можно трактовать и так, и так, в зависимости от того как делается деление по входу или по выходу.

DG>
DG>template<typename T>
DG>T Sum(typename std::vector<T>::iterator begin, typename std::vector<T>::iterator end)
DG>

Не соглашусь. Методы Sum и Add2 не могут работать для любого типа без специального кода.

S>> т.к. невозможно складывать значения обобщенным образом, не имея специальной информации о типе. Класть их в кортеж — можно.


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

Как бы эта информация берется из типа элемента, потому сам вектор ни в каких дописываниях для элементов некоторого типа не нуждается. Можем смело считать вектор образцом параметрического полиморфизма, задвинув под ковер его специализацию для bool-ов.
Re[4]: Функциональное метапрограммирование
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 22.02.12 21:25
Оценка:
B>В-четвертых, я не усмотрел там рекурсии. И в языке и в преобразовании она обычно присутствует.

в большинстве случаев от рекурсии лучше переходить к итерированию по дереву.
для такого итерирования достаточно тривиально доказывается конечность алгоритма, в отличии от рекурсии.
Re[8]: Функциональное метапрограммирование
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 22.02.12 21:29
Оценка:
S>Как бы эта информация берется из типа элемента, потому сам вектор ни в каких дописываниях для элементов некоторого типа не нуждается.

ню-ню
расскажи, пожалуйста, с каких пор ссылка на тип перестала быть типом? и с каких пор можно определить вектор для типа int& (std::vector<int&>)?
Re[9]: Функциональное метапрограммирование
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.02.12 21:49
Оценка:
Здравствуйте, DarkGray, Вы писали:

S>>Как бы эта информация берется из типа элемента, потому сам вектор ни в каких дописываниях для элементов некоторого типа не нуждается.


DG>ню-ню

DG>расскажи, пожалуйста, с каких пор ссылка на тип перестала быть типом? и с каких пор можно определить вектор для типа int& (std::vector<int&>)?
Хорошо, не будем считать вектор образцом параметрического полиморфизма. Но вместе с ним и List<T>, И Tuple<T> и т.п.
Re[8]: Функциональное метапрограммирование
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 22.02.12 21:54
Оценка:
S>Не соглашусь. Методы Sum и Add2 не могут работать для любого типа без специального кода.

так же можешь рассказать, почему std::vector не работает в следующих случаях:
class Z
{
private:

    Z& operator =(const Z& z) {return *this;}

};

int _tmain(int argc, _TCHAR* argv[])
{

    std::vector<Z> v4(10);
    std::vector<Z> v5(v4.begin(), v4.end());

    return 0;
}


int _tmain(int argc, _TCHAR* argv[])
{

typedef int (F)(void);

    std::vector<F> v4(10);
    std::vector<F> v5(v4.begin(), v4.end());

    return 0;
}


ps
а не работает оно всё по той же причине, нема для этих типов необходимо для вектора функционала
Re[10]: Функциональное метапрограммирование
От: DarkGray Россия http://blog.metatech.ru/post/ogni-razrabotki.aspx
Дата: 22.02.12 21:57
Оценка:
S>Хорошо, не будем считать вектор образцом параметрического полиморфизма. Но вместе с ним и List<T>, И Tuple<T> и т.п.

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