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>
Это неплохо выглядит. А предыдущий пример это что ?
Вообще спирит, судя по доке, построен на комбинаторах парсеров. Отсюда совершенно не ясно, как он может являться аргументом против монад, если сам он именно монаду и представляет.
Как сказал Синклер, разговор давно перешел в плоскость "в С++ нет ООП, есть только данные и методы"
Похоже, "монады не нужны" оказалось большим преувеличением
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Ааа, понял о чём речь, как раз в стиле Спирита задачки. ))) Согласен, полезная и вполне реализуемая вещь. Причём реализуемая тривиально прямо сейчас, если отказаться от идеи написания полноценного xml парсера, а реализовать решения конкретных задачек (типа двух примеров выше).
Я об этом и говорил с самого начала — я могу делать такие решения на коленке для каждого частного случая. Но это всё равно как разбирать регулярные выражения без Regex-библиотеки: работает в простых случаях, а шаг вправо/влево — и объём кода резко возрастает.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[47]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>А почему нет? Просто нужно понимать, что как только у нас появилось undefined где-то в выражении, так сразу всё выражение стало undefined. А в тех немногих местах, где нужно оставить "значение по умолчанию", отличное он undefined, пишется ручной код.
Я о том, что эти места будут не видны "невооруженным глазом". А особенно хорошо, если язык поддерживает вывод типов. Изменив, например, тип результата функции, мы разом изменяем семантику кода во многих местах. А компилятор нам не подскажет — семантика изменилась, но синтаксис подходит и старый... Ну хз, может я слишком перестраховываюсь, ведь эти рассуждения справедливы и в других случаях (Int32 заменили на Int64, например).
Re[49]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Монада будет принимать решения в тех местах, где это право ей делегируется явным вызовом bind. EP>То есть если код не был написан специальным образом — его придётся менять, bind'ы автоматом не расставятся.
Как я понял, Sinclair настаивает как раз на неизменном коде.
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Это неплохо выглядит. А предыдущий пример это что ?
Я его упростил.
I>Вообще спирит, судя по доке, построен на комбинаторах парсеров. Отсюда совершенно не ясно, как он может являться аргументом против монад, если сам он именно монаду и представляет.
Комбинация парсеров — это не обязательно монада. Это может быть например аппликативным функтором (суперкласс монад, т.е. более общая структура).
Чтобы называть монадой, нужно как минимум найти нетривиальный bind.
I>Как сказал Синклер, разговор давно перешел в плоскость "в С++ нет ООП, есть только данные и методы" I>Похоже, "монады не нужны" оказалось большим преувеличением
А в каком смысле было "монады не нужны"? Монада это математическая структура.
1. Не нужно знать такое понятие?
2. Не нужен do-сахар?
3. Не надо требовать в интерфейсе монады, там где достаточно более общих структур?
Re[50]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, AlexRK, Вы писали:
EP>>Монада будет принимать решения в тех местах, где это право ей делегируется явным вызовом bind. EP>>То есть если код не был написан специальным образом — его придётся менять, bind'ы автоматом не расставятся. ARK>Как я понял, Sinclair настаивает как раз на неизменном коде.
Вот, например, упрощённый вариант кода выше:
accumulate a = foldl (+) 0 a
Как сделать так, чтобы он работал на [Maybe Int] без изменений?
(естественно речь не про вытаскивание всех значений снаружи функции и её вызов с обычным списком [Int])
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Реальность примерно такая — на динамических языках как правило надо кода гнать в разы меньше, а иногда даже на порядки. Собтсвенно смотри сам — спирит сливает даже самопалу на JS.
Вот это уже действительно похоже на сказки. )))
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Записывать нужно так, что бы было легко прочесть, а не что бы строчек было меньше. Эдак окажется что все программы на всех языках будут в одну строку.
А что же ты тогда сам изначально БНФ записал в строчку? )))
I>Шо, в самом деле ? А я то думал это в любом реактивном парсере можно
В твоих примерах я этого не видел. )
I>Я же давал ссылку — там именно такая функция и приведена. Что еще надо, если та не подходит ?
Это где она одно число выводит? )))
I>Будешь смеяться, я и это показл. Парсер возвращает пару значение-остаток. Для числа значением будет число, представь себе весь ужас. Для скобки будет скобка и тд и тд.
Ну вот покажи пример аналогичный тем моим. Ну т.е. парсим инты разделённые запятыми и выводим их и среднее за всё время. Простейшая задачка, решаемая в пару строк, как я и показал. Интересно как будет выглядеть решение на базе тех твоих библиотек.
I>С железом всё крайне консервативно. Типичный железячник пишет такие простыни императивного кода, которые никто, кроме него, прочесть не может. Единственное достоинство — оно как то работает.
I>FRP нужно для описания поведения и реакции на события некоторой системы. Раз в робототехнике, по твоим словам, это не надо, ну значит робототехника до этого еще не доросла.
Очень сомнительный пример. Автор в начале развивает крайне кривую архитектуру (тучи разных ajax запросов особенно радуют), а потом успешно с ней борется с помощью сторонней библиотеки. В то время как данная задача решалась уже тысячи раз, причём и без подобных библиотек и без описанных в начале статьи ужасов.
Re[65]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Подход как раз именно один и тот же, это recursive descent. И я даже пудозреваю, что спирит это тоже реализация через комбинаторы парсеров, только в компайлтайм.
Вот именно что в компайлтайм. Это и есть принципиальная разница, а не разница в том что компилятор C++ позволяет создавать код эффективнее чем C#.
Re[41]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Ikemefula, Вы писали:
I>Не проще В моем случае надо понять только грамматику. В твоем — дополнительно к этому приседания с состоянием. I>Да и вообще, сколько смотрю, вот не могу понять, как твой вариант
Ну по крайне мере он заметно короче. ))) А остальное уже дело вкуса. )
I>Это абсолютно неважно — ты сказал что монады не нужны и сам же в конце концов предложил использовать монаду.
Это ты короутины что ли монадами обозвал? ) При таком раскладе тогда надо считать и все коллекции в stl монадами, да исключения тогда тоже монада и т.п... Весь C++ тогда состоит из сплошных монад. ))) Но мы вроде как в этой темке обсуждали явные монады с вполне конкретными свойствами, а не некую их аналогию из императивных языков. Так вот явные монады в C++ ввести можно без проблем (как показывалось уже в этой темке), но короутины, исключения или скажем std::list — это явно не оно. )))
I>Твоя функция Analyze выдохнется через полтора дня, когда окажется, что требования поменялись и все надо будет переписать. А без короутины количество кода будет просто конским.
Пока что практика показывает обратное. )
Re[45]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Sinclair, Вы писали:
S>И? Дальше-то что? Ну вот написал Петя такую функцию Apply для своего optional. А мне-то как этим пользоваться? S>Вот у меня был код на обычных big_integer: S>
S>Я решил заменить их на option<big_integer>. Как теперь будет выглядеть мой код?
Хм, очень странный пример, если смотреть с твоих позиций. Потому как именно при использование монад данный код придётся существенно переделывать. Конечно же и при использование функции вида Apply тоже надо переделывать, т.к. это тоже в общем то функциональный подход (хотя и без монад). Но кроме этого в языке есть и другие способы (см. ниже). Но если уж ты спросил именно про Apply, то всё же отвечу для порядка, хотя естественно я бы не стал подобную фигню использовать:
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]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, akava, Вы писали:
A>Тогда код Синклера никак не поменяется, но использоваться будет новая функция, созданная компилятором.
Тот его код как раз очень даже поменяется, т.к. нам в начале надо будет выделить из него функцию (причём только с параметрами типа big_int). Т.е. например весь кусок этого кода не получится взять, а можно только то, что внутри for'a. Ну и соответственно надо будет поменять переменные на параметры функции и т.п... В общем смысловая то часть естественно не поменяется, но переколбасить код надо будет очень существенно.
Re[67]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Полиморфные лямбды уже есть, концепции-lite скоро будут. Надо двигаться дальше — модули, compile-time reflection, корутины, макросы, мульти-методы и т.д.
Да, да, всё это хочу. )))
Кстати, это у нас уже практически полноценный D получается, только без потери гигантской инфраструктуры C++. Ещё бы только строки в шаблоны по человечески, плюс аналог функции mixin, и можно начинать творить чудеса. )))
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, 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]: Есть ли вещи, которые вы прницпиально не понимаете...
_>Это всё понятно. Но я вообще то как раз и спрашивал, а какой уже у нас будет тут код на языке позволяющем контроль эффектов? В чём будет его преимущество над кодом выше и т.п...
Отвечу как практик на эрланге, языке относительно бедном, поэтому ответ будет "от противного".
Во-первых, я хочу гарантировать чистоту processEventOrFail относительно определенных типов эффектов (они должны быть аккумулированы в Effects, в то время как другие — такие как чтение разделяемых глобальных данных или логирование — допустимы) на стадии компиляции или статического анализа. В эрланге это как минимум сложно, приходится решать административно.
Во-вторых, я вынужден вносить Effects внутрь State, так как иначе связывание кода внутри processEvent становится очень громоздким засчет необходимости передавать, возвращать и аккумулировать Effects. Это уродливый костыль с очевидными недостатками (например невозможно явно отличить функции State -> State с эффектами от функций без эффектов), но видимо лучшее практическое решение в отсутствие монад.
А в хаскелле и то и другое не проблема.
Re[46]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Хм, очень странный пример, если смотреть с твоих позиций. Потому как именно при использование монад данный код придётся существенно переделывать.
Зачем?
_>Конечно же и при использование функции вида Apply тоже надо переделывать, т.к. это тоже в общем то функциональный подход (хотя и без монад). Но кроме этого в языке есть и другие способы (см. ниже). Но если уж ты спросил именно про Apply, то всё же отвечу для порядка, хотя естественно я бы не стал подобную фигню использовать: _>
_>Apply со многими аргументами естественно без проблем выражается через через Apply для одного. Кстати, в C++ это ещё и можно записать сразу для всех видов монад в принципе, ну а в C# придётся записывать для каждого. Но это так, просто для общей картины.
В том-то и дело, что в языках без поддержки монад приходится вот так вот извращаться. Как только мы выйдем за пределы начальной школы, где формулы ограничены двумя аргументами, у нас объём кода, привнесённого apply, начнёт превышать объём оригинального кода.
А в языке, где монады — первоклассная сущность, весь heavy lifting должен делать компилятор.
_>А вот если воспользоваться "тупым императивным способом" и просто переопределить все нужные операторы для optional, то можно вообще не менять ни одну букву. Причём это естественно будет подходить сразу для всех типов. Что-то вроде: _>
Да, в С++ конкретно это место будет работать — потому что неинстанциированные шаблоны не компилируются, поэтому отсутствующие для T операторы будут отсутствовать и для optional<T>. К сожалению, это не коснётся пользовательских функций, поэтому прикладному программисту придётся выписывать либо Apply руками в каждое место применения, либо руками лифтить все нужные функции (см. System.Math для маленького примера. Реальная мат.библиотека будет содержать на порядок больше)
_>Кстати, а в языке D все эти операторы можно реализовать сразу одной функций, т.к. там вид оператора передаётся просто как параметр (времени компиляции естественно) в функцию.
Это всё паллиатив. Хардкорность монад — именно в том, что они имеют специальную семантику, и предоставляют определённые гарантии. Благодаря этому компилятор может втыкать Apply там, где нужно, не дожидаясь ручной подсказки от программиста.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[48]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали: _>Тот его код как раз очень даже поменяется, т.к. нам в начале надо будет выделить из него функцию (причём только с параметрами типа big_int). Т.е. например весь кусок этого кода не получится взять, а можно только то, что внутри for'a. Ну и соответственно надо будет поменять переменные на параметры функции и т.п... В общем смысловая то часть естественно не поменяется, но переколбасить код надо будет очень существенно.
Вот я как раз хочу, чтобы не надо было переколбашивать. И мне кажется, что как раз монады — путь к успеху.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[68]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, alex_public, Вы писали:
_>Мммм если целая индустрия работает по одним правилам, и ты один считаешь что им всем надо бы работать по другому, то как ты думаешь, какая вероятность что прав именно ты? )
Безотносительно конкретного вопроса, хотелось бы предостеречь против
1. Использования голосований (в т.ч. в виде статистики использования) для решения технических вопросов. Это очевидно нерелевантная аргументация — иначе мы были бы вынуждены признать PHP наиболее технически совершенным средством для веб-разработки.
2. Отсылки к промышленным применениям. Природа встраиваемых систем такова, что в них всегда предпочитают надёжное новому. Даже если новое решение в 100 раз лучше существующего, ему потребуется значительное время на внедрение.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[62]: Есть ли вещи, которые вы прницпиально не понимаете...
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Вообще спирит, судя по доке, построен на комбинаторах парсеров. Отсюда совершенно не ясно, как он может являться аргументом против монад, если сам он именно монаду и представляет.
EP>Комбинация парсеров — это не обязательно монада. Это может быть например аппликативным функтором (суперкласс монад, т.е. более общая структура). EP>Чтобы называть монадой, нужно как минимум найти нетривиальный bind.
Это ничего не меняет
I>>Как сказал Синклер, разговор давно перешел в плоскость "в С++ нет ООП, есть только данные и методы" I>>Похоже, "монады не нужны" оказалось большим преувеличением
EP>А в каком смысле было "монады не нужны"? Монада это математическая структура. EP>1. Не нужно знать такое понятие? EP>2. Не нужен do-сахар? EP>3. Не надо требовать в интерфейсе монады, там где достаточно более общих структур?
Изначально было так — "монады не нужны" потому что всё можно написать императивно.