
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[216.73.216.207] |
![]() |
|
Страницы: (31) 1 [2] 3 4 ... 30 31 ( Перейти к последнему сообщению ) |
Сообщ.
#16
,
|
|
|
Сообщ.
#17
,
|
|
|
А он поддерживает списки? ОК, попытаюсь поподробнее.
![]() ![]() def pifagor = sqrt . + . @ sqr pifagor : <3, 5> # пример использования ![]() Цитата wormball @ Лучше книжки читать. Теория -- это аппликативная вычислительная модель, лямбда-исчисление (особенно важда редукция лямбда-термов), комбинаторы, теория вычислимых функций (это уже не обязательно, хоть и интересно). Если серьезно заинтересуешься этой темой, могу скинуть список литературы и сами книги. Что в интернете можно почитать про функциональное и декларативное программирование? Цитата wormball @ Да. Если на пальцах, декларативное программирование -- это общая концепция, когда ты говоришь системе "что делать", а она уже сама решает задачу, в противоположность императивному программированию, где программы являются последовательностью инструкций, модифицирующих память. Функциональное программирование -- подмножество декларативного, основано на аппликативной вычислительной модели. Существует еще логическое программирование (например Пролог).Если я ничего не путаю, функциональное и декларативное программирование - две большие разницы? Цитата wormball @ Да ладно, вполне нормальное обсуждение. Кстати, если кто-то ещё не понял. Я не являюсь фанатичным поклонником Форта и затеял этот разговор не с целью заставить всех перейти на Форт, а именно выяснить, каким должен быть идеальный язык и какие языки больше всего претендуют на это звание. ![]() Добавлено Цитата Flex Ferrum @ Расшифруй, плз... ![]() ![]() def simple = and . @ % . distl . <id, tl . iota . dec . id> В данном случае при вызове функции "simple : 5" (5 -- объект, к которому применяется функция) происходит следующее (опишу последовательно редукцию): ![]() ![]() and . @ % . distl . <5, tl . iota . dec . 5> and . @ % . distl . <5, tl . iota . 4> and . @ % . distl . <5, tl . <1, 2, 3, 4>> and . @ % . distl . <5, <2, 3, 4>> and . @ % . <<5, 2>, <5, 3>, <5, 4>> # так работает distl and . <% . <5, 2>, % . <5, 3>, % . <5, 4>> and . <1, 2, 1> T # вычисление закончено, T означает true, F -- false Цитата Flex Ferrum @ Ну, программы на функциональных языках обычно в 4-10 раз короче, чем на императивных, что ведет к улучшению качества кода и упрощению сопровождения. При этом они зачастую более понятны (если конечно уметь программировать в функ. стиле). В функциональном программировании нет понятия переменной (программы прозрачны по ссылкам), нет понятия поток управления. Соответственно, исключаются многие виды ошибок. К этому остается добавить, что функ. языки отлично распараллеливаются. Но есть конечно и проблемы. Спорный вопрос - что лучше. Добавлено Наверное многим это паказалось программированием через одно место, но это всегда так поначалу кажется. ![]() ![]() |
Сообщ.
#18
,
|
|
|
Цитата Relan @ Объявлена функция simple (с помощью ключевого слова def), после знака равенства идет ее тело. Очень важно: это НЕ присваивание! это равенство по определению. Точка означает композицию. Вычисление идет справа налево. Угловые скобки означают список, его элементы разделяются запятой. Функция id -- identity -- тождественная функция, которая возвращает свой аргумент, который будет передан функции simple при ее вызове. dec -- уменьшение значения, которое вернула id на единицу. iota создает список из чисел от 1 до значения аргумента. tl "откусывает" от этого списка первый элемент. distl формирует список пар элементов, где на первом месте будет первый аргумент, на втором -- все остальные (поясню ниже). Форма "@ %" означает применение функции % (деление по модулю) к каждому элементу списка. and -- логическое И. Но тут получается, что у функционального языка должен быть достаточно объемный набор встроенных функций/операторов. Я к тому, что для того же С/С++ есть правило, что частью языка становится только то, что не может быть (или может, но очень сложно) реализовано посредством уже имеющегося набора. Я, конечно, не хочу сказать, что С++ минималистичен, но... Цитата Relan @ Ну, программы на функциональных языках обычно в 4-10 раз короче, чем на императивных, что ведет к улучшению качества кода и упрощению сопровождения. При этом они зачастую более понятны (если конечно уметь программировать в функ. стиле). В функциональном программировании нет понятия переменной (программы прозрачны по ссылкам), нет понятия поток управления. Соответственно, исключаются многие виды ошибок. К этому остается добавить, что функ. языки отлично распараллеливаются. Но есть конечно и проблемы. Я потому и говорю - спорный вопрос. По идее (запасясь достаточным объемом терпения и времени) я могу написать для С++ библиотеку, которая будет работать схожим образом. В конце концов - императивный/декларативный/функциональный - это лишь способы формализации задачи. Ведь могу же я в С++ написать: ![]() ![]() #include <boost/lambda.hpp> using namespace boost; //... std::list<int> some_list; std::for_each(some_list.begin(), some_list.end(), std::cout << _1); //... Чем не лямбда-функция? |
Сообщ.
#19
,
|
|
|
Цитата Flex Ferrum @ Ну да. Нужны библиотеки, как и для всякого языка. Но тут получается, что у функционального языка должен быть достаточно объемный набор встроенных функций/операторов. Цитата Flex Ferrum @ В моей реализации есть пародия на стандартную библиотеку, которая подключается автоматически и где определены многие функции (написанные на самом FP естественно, например dec и and). А в интерпретаторе остался лишь необходимый минимум. Впрочем, это уже детали реализации. Ничто не мешает следовать принципу минимализма, сформулированному тобой. Я к тому, что для того же С/С++ есть правило, что частью языка становится только то, что не может быть (или может, но очень сложно) реализовано посредством уже имеющегося набора. Цитата Flex Ferrum @ Ну, можно и на С писать в объектно-ориентированном стиле. Но вот удобно ли? По идее (запасясь достаточным объемом терпения и времени) я могу написать для С++ библиотеку, которая будет работать схожим образом. Цитата Flex Ferrum @ Тем, что 1) объявлена переменная, 2) происходит изменение среды 3) явно описан поток управления. Как ни извращайся, а на С++ писать в истинно функциональном стиле не получится. Чем не лямбда-функция? |
Сообщ.
#20
,
|
|
|
Цитата Relan @ Тем, что 1) объявлена переменная, 2) происходит изменение среды 3) явно описан поток управления. 1) Как тебе такой вариант: ![]() ![]() template<typename C, typename F> void for_each(const C& c, F f) { std::for_each(c.begin(), c.end(), f); } int main(int, char**) { for_each(boost::assign::list_of(1)(2)(3)(4)(5)(6)(7), std::cout << boost::lambda::_1 << "\n"); return 0; } Добавлено Проверено - работает. Выдает честные ![]() ![]() 1 2 3 4 5 6 7 Press any key to continue 2) Что понимается под "изменением среды"? 3) Каким образом я описал поток управления? |
Сообщ.
#21
,
|
|
|
Цитата Flex Ferrum @ Прикольно. Даже догадываюсь как это сделано. 1) Как тебе такой вариант ![]() Цитата Flex Ferrum @ Любая модификация памяти. Например, в for_each происходит инкремент итератора. 2) Что понимается под "изменением среды"? Цитата Flex Ferrum @ В Стандарте ведь определена ассоциативность операторов, в частности "<<"? 3) Каким образом я описал поток управления? ![]() |
Сообщ.
#22
,
|
|
|
Цитата Relan @ Любая модификация памяти. Например, в for_each происходит инкремент итератора. Т. е. ты хочешь сказать, что при интерпретации твоей программы, написанной на функциональном языке, среда исполнения никак не меняется? Не модифицируются списки (пусть и временные), промежуточные результаты никак не сохраняются? Цитата Relan @ В Стандарте ведь определена ассоциативность операторов, в частности "<<"? Да. Определена. Согласен. Цитата Relan @ В функциональном языке таких жестких ограничений быть не должно, они там будут просто бессмысленны. Это как? Т. е. ты не можешь точно сказать - какой из операндов операции будет вычеслен в первую очередь? Так? А как же твоя фраза: Цитата Relan @ Вычисление идет справа налево. Добавлено Кстати, вот что написано в стандарте про for_each: Цитата Applies f to the result of dereferencing every iterator in the range [first, last), starting fromfirstand proceeding tolast - 1. Т. е. стандарт не специфицирует - как именно функтор будет применен к каждому элементу диапазона. По этому инкремент итератора - это (можно считать) детали и особенность конкретной реализации. Добавлено Цитата Relan @ Прикольно. Даже догадываюсь как это сделано. Вот еще вариантик: ![]() ![]() template<typename C, typename F> void for_each(const C& c, F f) { std::for_each(c.begin(), c.end(), f); } template<typename T> class ContWrapper : public T { public: ContWrapper<T>& operator ,(const typename T::value_type& v) { insert(end(), v); return *this; } }; template<typename T> ContWrapper<T> seq() {return ContWrapper<T>();} int main(int, char**) { for_each((seq<std::list<int> >(), 5, 2, 3, 1, 9, 20, -10, 8), std::cout << boost::lambda::_1 << "\n"); std::cout << std::endl; for_each((seq<std::set<int> >(), 5, 2, 3, 1, 9, 20, -10, 8), std::cout << boost::lambda::_1 << "\n"); return 0; } Выдает, опять же: ![]() ![]() 5 2 3 1 9 20 -10 8 -10 1 2 3 5 8 9 20 |
Сообщ.
#23
,
|
|
|
Цитата Relan @ Если серьезно заинтересуешься этой темой, могу скинуть список литературы и сами книги. Давай. Цитата Relan @ Ну, программы на функциональных языках обычно в 4-10 раз короче А как насчёт скорости исполнения? Добавлено Цитата Relan @ После нескольких лет императивного программирования научиться думать на функциональном языке ОЧЕНЬ сложно. Почти также сложно, как бросить курить Напоминило древнюю поговорку - "Легче бросит курить, чем Фортран 77" |
Сообщ.
#24
,
|
|
|
Цитата Flex Ferrum @ Я наверное неправильно выразился. В функ. языке объект однажды получает значение и больше никогда не изменяется вплоть до разрушения. Т. е. ты хочешь сказать, что при интерпретации твоей программы, написанной на функциональном языке, среда исполнения никак не меняется? Не модифицируются списки (пусть и временные), промежуточные результаты никак не сохраняются? Цитата Flex Ferrum @ Да. Просто нет необходимости знать порядок вычислений операндов, т. к. побочные эффекты в чистых функ. языках отсутствуют. По поводу моей форазы -- имелась в виду функциональная форма композиции, ее нотация. Проводя аналогию с математикой: в выражении f(g(x)) мы ведь не можем начать вычисления ф-ции f до того, как будет вычислена g. Однако в выражении f(g(x), h(x)) мы можем вычислять g и h в любом порядке, т. к. математические функции не модифицируют х. Так же и в функ. программе. Т. е. ты не можешь точно сказать - какой из операндов операции будет вычеслен в первую очередь? Так? А как же твоя фраза Цитата Flex Ferrum @ Ну, в принципе, можно переписать for_each так, чтобы использовалась рекурсия. Тогда это будет функ. стиль. Но for_each обычно используется либо для модификации последовательности, либо ради какого-то побочного эффекта. И то, и другое не вписывается в чистое функ. программирование.Т. е. стандарт не специфицирует - как именно функтор будет применен к каждому элементу диапазона. По этому инкремент итератора - это (можно считать) детали и особенность конкретной реализации. Кстати, в функ. языках нет циклов по причине того, что запрещено модифицировать переменные. Вместо них используется рекурсия. Добавлено Цитата Flex Ferrum @ Всё это, конечно, замечательная гимнастика для ума, но на том же FP это делается так: Выдает, опять же ![]() ![]() @ print : <5, 2, 3, 1, 9, 20, -10, 8> @ print . sort : <5, 2, 3, 1, 9, 20, -10, 8> Цитата antigen @ ОК, чуть попозжа доберусь до своей библиотеки и сделаю подборку. Давай. Цитата antigen @ Скорость исполнения программ на функ. языках обычно ниже, чем на императивных, т. к. последние по своей природе ближе к архитектуре машины. Хотя сейчас уже есть неплохие компиляторы Лиспа, не очень сильно отстающие в этом плане от С и С++. А как насчёт скорости исполнения? |
Сообщ.
#25
,
|
|
|
Цитата Relan @ Я наверное неправильно выразился. В функ. языке объект однажды получает значение и больше никогда не изменяется вплоть до разрушения. Ага. Вот так понятнее. Цитата Relan @ Да. Просто нет необходимости знать порядок вычислений операндов, т. к. побочные эффекты в чистых функ. языках отсутствуют. По поводу моей форазы -- имелась в виду функциональная форма композиции, ее нотация. Проводя аналогию с математикой: в выражении f(g(x)) мы ведь не можем начать вычисления ф-ции f до того, как будет вычислена g. Однако в выражении f(g(x), h(x)) мы можем вычислять g и h в любом порядке, т. к. математические функции не модифицируют х. Так же и в функ. программе. Ты можешь мне не верить, но в выражении вида f(g(x), h(x)), записанном на языке С++, порядок вычисления операндов не определен. Точно также, как и в приведенных примерах. Если бы я написал: Цитата Flex Ferrum @ seq<std::set<int> >(), f(5), f(2), f(3), f(1), f(9), f(20), f(-10), f(8)) То порядок вызова функций f я наперед не знаю. Я лишь знаю, что операторы ',' будут вызваны последовательно один за другим и им в определенном порядке будут переданы результаты вычисления. Но не больше. ![]() Цитата The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argu- ment expression list is unspecified. (5.2.2, clause 8). А потому строчка ![]() ![]() int i = 1; for_each((seq<std::list<int> >(), ++ i, ++ i, ++ i, ++ i, ++ i, ++ i, ++ i, ++ i), std::cout << boost::lambda::_1 << "\n"); Выводит... ![]() ![]() 9 9 9 9 9 9 9 9 а ![]() ![]() int ff(int volatile& i) { return i ++; } int main(int, char**) { int volatile i = 1; for_each((seq<std::list<int> >(), ff(i), ff(i), ff(i), ff(i), ff(i), ff(i), ff(i), ff(i)), std::cout << boost::lambda::_1 << "\n"); ![]() ![]() 8 7 6 5 4 3 2 1 Вот такие вот "чудеса". ![]() Цитата Relan @ Ну, в принципе, можно переписать for_each так, чтобы использовалась рекурсия. Тогда это будет функ. стиль. Но for_each обычно используется либо для модификации последовательности, либо ради какого-то побочного эффекта. И то, и другое не вписывается в чистое функ. программирование. ![]() Добавлено Цитата Relan @ Всё это, конечно, замечательная гимнастика для ума, но на том же FP это делается так: @ print : <5, 2, 3, 1, 9, 20, -10, 8> @ print . sort : <5, 2, 3, 1, 9, 20, -10, 8> Первый - соглашусь. Второй - не эквивалентен, т. к. std::set != отсортированная последовательность, т. к. std::set - отсортированная последовательность уникальных элементов. Ок. Ну а если я хочу вывести на консоль последовательность, каждый элемент который увеличен на некоторую константу? Добавлено Да и кто мне мешает написать алгортм print: ![]() ![]() template<typename C> void print(const C& c) { std::for_each(c.begin(), c.end(), std::cout << _1 << "\n"); } который сделает мне тоже самое, но короче? |
Сообщ.
#26
,
|
|
|
Цитата Flex Ferrum @ Прошу прощения, если я где-то неясно излагаю, просто стараюсь не углубляться без необходимости. Блин, как-то аж неудобно читать лекции по программированию самому Flex Ferrum'у. Ага. Вот так понятнее. ![]() Цитата Flex Ferrum @ Знаю-знаю, что в С++ в данном случае запятая является разделителем аргументов, а не оператором "," (в котором ассоциативность определена). Я лишь привел пример, не надо его понимать буквально. Ну, пусть будет f(g(x) + h(x)), если это принципиально. Ты можешь мне не верить, но в выражении вида f(g(x), h(x)), записанном на языке С++, порядок вычисления операндов не определен. Цитата Flex Ferrum @ Это я и имел в виду. В функ. языках "функтор" не может модифицировать сами элементы.for_each - это немодифицирующий алгоритм. Т. е., конечно, если ты захочешь, то функтор будет модифицировать элементы последовательности. Цитата Flex Ferrum @ Конечно, просто в данном случае вывод будет таким же. Первый - соглашусь. Второй - не эквивалентен, т. к. std::set != отсортированная последовательность, т. к. std::set - отсортированная последовательность уникальных элементов. Цитата Flex Ferrum @ ФункцияНу а если я хочу вывести на консоль последовательность, каждый элемент который увеличен на некоторую константу? ![]() ![]() print . @ (+ . <id, `10>) : <8, 3, 7, 1> |
Сообщ.
#27
,
|
|
|
Цитата Relan @ Блин, как-то аж неудобно читать лекции по программированию самому Flex Ferrum'у. Ну, функциональное программирование прошло несколько в стороне от меня... ![]() Цитата Relan @ Ну, пусть будет f(g(x) + h(x)), если это принципиально. И в этом случае не определено - в каком порядке будут вычеслины g(x) и h(x). Т. е. это определено, если используется встроенный оператор +. А если перегруженный - то не определено. Тоже самое с оператором ','. Цитата Relan @ Это я и имел в виду. В функ. языках "функтор" не может модифицировать сами элементы. Так я же об этом дальше написал: Цитата Flex Ferrum @ Но обычно для этого есть другие - модифицирующие алгоритмы. например, std::transform. Цитата Relan @ Конечно, просто в данном случае вывод будет таким же. А как он будет выглядеть, если надо сохранить требование уникальности элементов? Цитата Relan @ print . @ (+ . <id, `10>) : <8, 3, 7, 1> Цитата Flex Ferrum @ ![]() ![]() for_each((seq<std::list<int> >(), 5, 2, 3, 1, 9, 20, -10, 8), std::cout << _1 + 10 << "\n"); std::cout << std::endl; for_each((seq<std::set<int> >(), 5, 2, 3, 1, 9, 20, -10, 8), std::cout << _1 + 10 << "\n"); ![]() ![]() |
Сообщ.
#28
,
|
|
|
Конечно же нет. Человеческий язык "ужасно" не однозначен. И такого счастья как вы предлагаете никому не надо. |
Сообщ.
#29
,
|
|
|
Flex Ferrum, назревает новый холивар "Функциональные языки против императивных"?
![]() |
Сообщ.
#30
,
|
|
|
Цитата Relan @ Flex Ferrum, назревает новый холивар "Функциональные языки против императивных"? ![]() Добавлено Вот если реализуется одна моя идейка - то можно будет попробовать С++ в качестве декларативного языка... |