Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Evgeny.Panasyuk Россия  
Дата: 12.01.14 16:37
Оценка: 68 (1)
Здравствуйте, Ikemefula, Вы писали:

I>Вот смотри, твой спирит, я даже не знаю, не то смеяться, не то плакать.

I>
I>    auto const expression_def =
I>        term
        >>> *(   (char_('+') >> term)
I>            |   (char_('-') >> term)
I>            )
I>        ;
 
I>    auto const term_def =
I>        factor
        >>> *(   (char_('*') >> factor)
I>            |   (char_('/') >> factor)
I>            )
I>        ;
 
I>    auto const factor_def =
I>            uint_
I>        |   '(' >> expression >> ')'
I>        |   (char_('-') >> factor)
I>        |   (char_('+') >> factor)
I>        ;
I>

I>вот BNF:
I>
I>expr = term | term '+' term | term '-' term
I>term = factor '*' factor | factor '/' factor
I>factor = number | '(' expr ')' | '-' factor | '+' factor
I>number = digit {digit}
I>digit = '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
I>

I>Итого — в спирите раз в 7-8 раз больше кода чем в бнф грамматике, при том что два правила сидят в самой либине — digit и uint, если их добавить, кода будет в 10 раз больше
I>А вот фокус — та же грамматика на комбинаторах
I>
I>var term = empty(); 
I>var unary = empty();
I>var number = rep1(range('0..9'))
I>var expr = or(term, seq(term, or('-+'), term))
I>var term = term.overWrite(seq( factor, or('*/'), factor))
I>var factor = or(number, seq('(',expr,')'), unary)
I>var unary = unary.overWrite(seq(or('-+'), factor))
I>


Вот spirit, со своими number и digit:
expr   = term % sign;
term   = factor % (lit('*') | '/');
factor = number | '('>>expr>>')' | sign>>factor;
number = +digit;
digit  = lit('0')|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9';
sign   = lit('+')|'-';
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 12.01.14 16:56
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Вот spirit, со своими number и digit:

EP>
EP>expr   = term % sign;
EP>term   = factor % (lit('*') | '/');
EP>factor = number | '('>>expr>>')' | sign>>factor;
EP>number = +digit;
EP>digit  = lit('0')|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9';
EP>sign   = lit('+')|'-';
EP>


Это неплохо выглядит. А предыдущий пример это что ?

Вообще спирит, судя по доке, построен на комбинаторах парсеров. Отсюда совершенно не ясно, как он может являться аргументом против монад, если сам он именно монаду и представляет.

Как сказал Синклер, разговор давно перешел в плоскость "в С++ нет ООП, есть только данные и методы"

Похоже, "монады не нужны" оказалось большим преувеличением
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.01.14 17:08
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Ааа, понял о чём речь, как раз в стиле Спирита задачки. ))) Согласен, полезная и вполне реализуемая вещь. Причём реализуемая тривиально прямо сейчас, если отказаться от идеи написания полноценного xml парсера, а реализовать решения конкретных задачек (типа двух примеров выше).

Я об этом и говорил с самого начала — я могу делать такие решения на коленке для каждого частного случая. Но это всё равно как разбирать регулярные выражения без Regex-библиотеки: работает в простых случаях, а шаг вправо/влево — и объём кода резко возрастает.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
От: AlexRK  
Дата: 12.01.14 17:58
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А почему нет? Просто нужно понимать, что как только у нас появилось undefined где-то в выражении, так сразу всё выражение стало undefined. А в тех немногих местах, где нужно оставить "значение по умолчанию", отличное он undefined, пишется ручной код.


Я о том, что эти места будут не видны "невооруженным глазом". А особенно хорошо, если язык поддерживает вывод типов. Изменив, например, тип результата функции, мы разом изменяем семантику кода во многих местах. А компилятор нам не подскажет — семантика изменилась, но синтаксис подходит и старый... Ну хз, может я слишком перестраховываюсь, ведь эти рассуждения справедливы и в других случаях (Int32 заменили на Int64, например).
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
От: AlexRK  
Дата: 12.01.14 17:59
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Монада будет принимать решения в тех местах, где это право ей делегируется явным вызовом bind.

EP>То есть если код не был написан специальным образом — его придётся менять, bind'ы автоматом не расставятся.

Как я понял, Sinclair настаивает как раз на неизменном коде.
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Evgeny.Panasyuk Россия  
Дата: 12.01.14 18:02
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Это неплохо выглядит. А предыдущий пример это что ?


Я его упростил.

I>Вообще спирит, судя по доке, построен на комбинаторах парсеров. Отсюда совершенно не ясно, как он может являться аргументом против монад, если сам он именно монаду и представляет.


Комбинация парсеров — это не обязательно монада. Это может быть например аппликативным функтором (суперкласс монад, т.е. более общая структура).
Чтобы называть монадой, нужно как минимум найти нетривиальный bind.

I>Как сказал Синклер, разговор давно перешел в плоскость "в С++ нет ООП, есть только данные и методы"

I>Похоже, "монады не нужны" оказалось большим преувеличением

А в каком смысле было "монады не нужны"? Монада это математическая структура.
1. Не нужно знать такое понятие?
2. Не нужен do-сахар?
3. Не надо требовать в интерфейсе монады, там где достаточно более общих структур?
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Evgeny.Panasyuk Россия  
Дата: 12.01.14 18:28
Оценка:
Здравствуйте, AlexRK, Вы писали:

EP>>Монада будет принимать решения в тех местах, где это право ей делегируется явным вызовом bind.

EP>>То есть если код не был написан специальным образом — его придётся менять, bind'ы автоматом не расставятся.
ARK>Как я понял, Sinclair настаивает как раз на неизменном коде.

Вот, например, упрощённый вариант кода выше:
accumulate a = foldl (+) 0 a
Как сделать так, чтобы он работал на [Maybe Int] без изменений?
(естественно речь не про вытаскивание всех значений снаружи функции и её вызов с обычным списком [Int])
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 12.01.14 22:19
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Реальность примерно такая — на динамических языках как правило надо кода гнать в разы меньше, а иногда даже на порядки. Собтсвенно смотри сам — спирит сливает даже самопалу на JS.


Вот это уже действительно похоже на сказки. )))
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 12.01.14 23:50
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Записывать нужно так, что бы было легко прочесть, а не что бы строчек было меньше. Эдак окажется что все программы на всех языках будут в одну строку.


А что же ты тогда сам изначально БНФ записал в строчку? )))

I>Шо, в самом деле ? А я то думал это в любом реактивном парсере можно


В твоих примерах я этого не видел. )

I>Я же давал ссылку — там именно такая функция и приведена. Что еще надо, если та не подходит ?


Это где она одно число выводит? )))

I>Будешь смеяться, я и это показл. Парсер возвращает пару значение-остаток. Для числа значением будет число, представь себе весь ужас. Для скобки будет скобка и тд и тд.


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

I>С железом всё крайне консервативно. Типичный железячник пишет такие простыни императивного кода, которые никто, кроме него, прочесть не может. Единственное достоинство — оно как то работает.


I>FRP нужно для описания поведения и реакции на события некоторой системы. Раз в робототехнике, по твоим словам, это не надо, ну значит робототехника до этого еще не доросла.


Мммм если целая индустрия работает по одним правилам, и ты один считаешь что им всем надо бы работать по другому, то как ты думаешь, какая вероятность что прав именно ты? )

I>вот два нормальных примера, которые еще раз внятно объясняют как это можно использовать

I>http://nullzzz.blogspot.com/2012/11/baconjs-tutorial-part-ii-get-started.html
I>http://nullzzz.blogspot.com/2012/11/baconjs-tutorial-part-i-hacking-with.html

Очень сомнительный пример. Автор в начале развивает крайне кривую архитектуру (тучи разных ajax запросов особенно радуют), а потом успешно с ней борется с помощью сторонней библиотеки. В то время как данная задача решалась уже тысячи раз, причём и без подобных библиотек и без описанных в начале статьи ужасов.
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 13.01.14 00:06
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Подход как раз именно один и тот же, это recursive descent. И я даже пудозреваю, что спирит это тоже реализация через комбинаторы парсеров, только в компайлтайм.


Вот именно что в компайлтайм. Это и есть принципиальная разница, а не разница в том что компилятор C++ позволяет создавать код эффективнее чем C#.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 13.01.14 00:24
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Не проще В моем случае надо понять только грамматику. В твоем — дополнительно к этому приседания с состоянием.

I>Да и вообще, сколько смотрю, вот не могу понять, как твой вариант

Ну по крайне мере он заметно короче. ))) А остальное уже дело вкуса. )

I>Это абсолютно неважно — ты сказал что монады не нужны и сам же в конце концов предложил использовать монаду.


Это ты короутины что ли монадами обозвал? ) При таком раскладе тогда надо считать и все коллекции в stl монадами, да исключения тогда тоже монада и т.п... Весь C++ тогда состоит из сплошных монад. ))) Но мы вроде как в этой темке обсуждали явные монады с вполне конкретными свойствами, а не некую их аналогию из императивных языков. Так вот явные монады в C++ ввести можно без проблем (как показывалось уже в этой темке), но короутины, исключения или скажем std::list — это явно не оно. )))

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


Пока что практика показывает обратное. )
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 13.01.14 01:53
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>И? Дальше-то что? Ну вот написал Петя такую функцию Apply для своего optional. А мне-то как этим пользоваться?

S>Вот у меня был код на обычных big_integer:
S>
S>for(int i=0; i<array.length(); i++)
S>{
S>  if (array[i]*array[i] > limit))
S>    sum+=array[i]*array[i];
S>}
S>

S>Я решил заменить их на option<big_integer>. Как теперь будет выглядеть мой код?

Хм, очень странный пример, если смотреть с твоих позиций. Потому как именно при использование монад данный код придётся существенно переделывать. Конечно же и при использование функции вида Apply тоже надо переделывать, т.к. это тоже в общем то функциональный подход (хотя и без монад). Но кроме этого в языке есть и другие способы (см. ниже). Но если уж ты спросил именно про Apply, то всё же отвечу для порядка, хотя естественно я бы не стал подобную фигню использовать:
for(int i=0; i<array.length(); i++) Apply(array[i], sum, [&](big_integer array_i, big_integer& sum_)
{
  if (array_i*array_i > limit))
    sum_+=array_i*array_i;
});

Apply со многими аргументами естественно без проблем выражается через через Apply для одного. Кстати, в C++ это ещё и можно записать сразу для всех видов монад в принципе, ну а в C# придётся записывать для каждого. Но это так, просто для общей картины.

А вот если воспользоваться "тупым императивным способом" и просто переопределить все нужные операторы для optional, то можно вообще не менять ни одну букву. Причём это естественно будет подходить сразу для всех типов. Что-то вроде:
template<typename T> auto operator+(const optional<T>& t1, const optional<T>& t2){return t1&&t2?*t1+*t2:optional<T>();}


Кстати, а в языке D все эти операторы можно реализовать сразу одной функций, т.к. там вид оператора передаётся просто как параметр (времени компиляции естественно) в функцию.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 13.01.14 02:09
Оценка:
Здравствуйте, akava, Вы писали:

A>Тогда код Синклера никак не поменяется, но использоваться будет новая функция, созданная компилятором.


Тот его код как раз очень даже поменяется, т.к. нам в начале надо будет выделить из него функцию (причём только с параметрами типа big_int). Т.е. например весь кусок этого кода не получится взять, а можно только то, что внутри for'a. Ну и соответственно надо будет поменять переменные на параметры функции и т.п... В общем смысловая то часть естественно не поменяется, но переколбасить код надо будет очень существенно.
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 13.01.14 02:23
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Полиморфные лямбды уже есть, концепции-lite скоро будут. Надо двигаться дальше — модули, compile-time reflection, корутины, макросы, мульти-методы и т.д.


Да, да, всё это хочу. )))

Кстати, это у нас уже практически полноценный D получается, только без потери гигантской инфраструктуры C++. Ещё бы только строки в шаблоны по человечески, плюс аналог функции mixin, и можно начинать творить чудеса. )))
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.01.14 06:04
Оценка: 2 (1)
Здравствуйте, AlexRK, Вы писали:
ARK>Я о том, что эти места будут не видны "невооруженным глазом".
Эти места будут сразу видны — там, где мы пытаемся выполнить конверсию из option<T> в T.
Наличие lifted операций просто помогает минимизировать последствия катастрофы. Там, где мы писали

int a = b + (c*d);

мы будем писать
int a = b + (c*d) ?? 42;

Но не
int a = (b ?? 42) + (c ?? 0) * (d ?? 0);

ARK>А особенно хорошо, если язык поддерживает вывод типов. Изменив, например, тип результата функции, мы разом изменяем семантику кода во многих местах.
Практически любой современный язык поддерживает вывод типов — по крайней мере, в пределах выражения.

ARK>А компилятор нам не подскажет — семантика изменилась, но синтаксис подходит и старый... Ну хз, может я слишком перестраховываюсь, ведь эти рассуждения справедливы и в других случаях (Int32 заменили на Int64, например).

Совершенно верно. А также при замене int на double, или double на Matrix4x4<double>.
Тут вопрос в том, что считать семантикой
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[34]: Есть ли вещи, которые вы прницпиально не понимаете...
От: meadow_meal  
Дата: 13.01.14 06:12
Оценка:
Здравствуйте, alex_public, Вы писали:

_>>
_>>...
_>>(NewState, Effects) = processEventOrFail(Event, State);
_>>applyEffects(Effects);
_>>return NewState;
_>>...
_>>


_>Это всё понятно. Но я вообще то как раз и спрашивал, а какой уже у нас будет тут код на языке позволяющем контроль эффектов? В чём будет его преимущество над кодом выше и т.п...


Отвечу как практик на эрланге, языке относительно бедном, поэтому ответ будет "от противного".

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

Во-вторых, я вынужден вносить Effects внутрь State, так как иначе связывание кода внутри processEvent становится очень громоздким засчет необходимости передавать, возвращать и аккумулировать Effects. Это уродливый костыль с очевидными недостатками (например невозможно явно отличить функции State -> State с эффектами от функций без эффектов), но видимо лучшее практическое решение в отсутствие монад.

А в хаскелле и то и другое не проблема.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.01.14 06:19
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Хм, очень странный пример, если смотреть с твоих позиций. Потому как именно при использование монад данный код придётся существенно переделывать.

Зачем?

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

_>
_>for(int i=0; i<array.length(); i++) Apply(array[i], sum, [&](big_integer array_i, big_integer& sum_)
_>{
_>  if (array_i*array_i > limit))
_>    sum_+=array_i*array_i;
_>});
_>

_>Apply со многими аргументами естественно без проблем выражается через через Apply для одного. Кстати, в C++ это ещё и можно записать сразу для всех видов монад в принципе, ну а в C# придётся записывать для каждого. Но это так, просто для общей картины.
В том-то и дело, что в языках без поддержки монад приходится вот так вот извращаться. Как только мы выйдем за пределы начальной школы, где формулы ограничены двумя аргументами, у нас объём кода, привнесённого apply, начнёт превышать объём оригинального кода.
А в языке, где монады — первоклассная сущность, весь heavy lifting должен делать компилятор.

_>А вот если воспользоваться "тупым императивным способом" и просто переопределить все нужные операторы для optional, то можно вообще не менять ни одну букву. Причём это естественно будет подходить сразу для всех типов. Что-то вроде:

_>
_>template<typename T> auto operator+(const optional<T>& t1, const optional<T>& t2){return t1&&t2?*t1+*t2:optional<T>();}
_>

Да, в С++ конкретно это место будет работать — потому что неинстанциированные шаблоны не компилируются, поэтому отсутствующие для T операторы будут отсутствовать и для optional<T>. К сожалению, это не коснётся пользовательских функций, поэтому прикладному программисту придётся выписывать либо Apply руками в каждое место применения, либо руками лифтить все нужные функции (см. System.Math для маленького примера. Реальная мат.библиотека будет содержать на порядок больше)

_>Кстати, а в языке D все эти операторы можно реализовать сразу одной функций, т.к. там вид оператора передаётся просто как параметр (времени компиляции естественно) в функцию.

Это всё паллиатив. Хардкорность монад — именно в том, что они имеют специальную семантику, и предоставляют определённые гарантии. Благодаря этому компилятор может втыкать Apply там, где нужно, не дожидаясь ручной подсказки от программиста.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.01.14 06:21
Оценка:
Здравствуйте, alex_public, Вы писали:
_>Тот его код как раз очень даже поменяется, т.к. нам в начале надо будет выделить из него функцию (причём только с параметрами типа big_int). Т.е. например весь кусок этого кода не получится взять, а можно только то, что внутри for'a. Ну и соответственно надо будет поменять переменные на параметры функции и т.п... В общем смысловая то часть естественно не поменяется, но переколбасить код надо будет очень существенно.
Вот я как раз хочу, чтобы не надо было переколбашивать. И мне кажется, что как раз монады — путь к успеху.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Sinclair Россия https://github.com/evilguest/
Дата: 13.01.14 06:31
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Мммм если целая индустрия работает по одним правилам, и ты один считаешь что им всем надо бы работать по другому, то как ты думаешь, какая вероятность что прав именно ты? )


Безотносительно конкретного вопроса, хотелось бы предостеречь против
1. Использования голосований (в т.ч. в виде статистики использования) для решения технических вопросов. Это очевидно нерелевантная аргументация — иначе мы были бы вынуждены признать PHP наиболее технически совершенным средством для веб-разработки.
2. Отсылки к промышленным применениям. Природа встраиваемых систем такова, что в них всегда предпочитают надёжное новому. Даже если новое решение в 100 раз лучше существующего, ему потребуется значительное время на внедрение.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 13.01.14 07:21
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

I>>Вообще спирит, судя по доке, построен на комбинаторах парсеров. Отсюда совершенно не ясно, как он может являться аргументом против монад, если сам он именно монаду и представляет.


EP>Комбинация парсеров — это не обязательно монада. Это может быть например аппликативным функтором (суперкласс монад, т.е. более общая структура).

EP>Чтобы называть монадой, нужно как минимум найти нетривиальный bind.

Это ничего не меняет

I>>Как сказал Синклер, разговор давно перешел в плоскость "в С++ нет ООП, есть только данные и методы"

I>>Похоже, "монады не нужны" оказалось большим преувеличением

EP>А в каком смысле было "монады не нужны"? Монада это математическая структура.

EP>1. Не нужно знать такое понятие?
EP>2. Не нужен do-сахар?
EP>3. Не надо требовать в интерфейсе монады, там где достаточно более общих структур?

Изначально было так — "монады не нужны" потому что всё можно написать императивно.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.