Функциональный стиль
От: realloc Россия  
Дата: 28.01.09 15:59
Оценка:
Как можно использовать subj в императивном языке (меня интересует С, С++)?
Если не сложно, приведите примеры небольших кусков кода, реализующих одно и тоже в виде:
(ни фига не функционально ) ====> (весьма функционально ).
Спасибо .
Re: Функциональный стиль
От: thesz Россия http://thesz.livejournal.com
Дата: 28.01.09 16:43
Оценка: 9 (2)
Здравствуйте, realloc, Вы писали:

R>Как можно использовать subj в императивном языке (меня интересует С, С++)?

R>Если не сложно, приведите примеры небольших кусков кода, реализующих одно и тоже в виде:
R>(ни фига не функционально ) ====> (весьма функционально ).
R>Спасибо .

Были глобальные переменные — стало протягивание состояния.

Было
int counter1 = 0;
int counter2 = 1000;
void init_counters (void) { counter1 = 0; counter2 = 1000; }
void count_event(void) { counter1 ++; }
int check_tries(void) { counter2 --; return (counter2 >= 0); }


Стало
typedef struct {
  int counter1 = 0;
  int counter2 = 1000;
} counters;
void init_counters (counters* c) { c->counter1 = 0; c->counter2 = 1000; }
void count_event(counters* c) { c->counter1 ++; }
int check_tries(counters* c) { c->counter2 --; return (c->counter2 >= 0); }


Линейное протягивание состояния функционально.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[2]: Функциональный стиль
От: DemAS http://demas.me
Дата: 28.01.09 18:44
Оценка:
"thesz" <49985@users.rsdn.ru> writes:

> Были глобальные переменные — стало протягивание состояния.


Как то это больше на полу-объектно-ориентированное программирование стало
похоже. Еще структуру заменить на класс, а функции сделать методами класса.

По теме — может статью Влада про LINQ посмотреть ?
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Функциональный стиль
От: realloc Россия  
Дата: 28.01.09 19:02
Оценка:
Здравствуйте, thesz, Вы писали:

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


R>>Как можно использовать subj в императивном языке (меня интересует С, С++)?

R>>Если не сложно, приведите примеры небольших кусков кода, реализующих одно и тоже в виде:
R>>(ни фига не функционально ) ====> (весьма функционально ).
R>>Спасибо .

T>Были глобальные переменные — стало протягивание состояния.


Угу, хорошо. А ещё есть, посложнее?

T>Линейное протягивание состояния функционально.


Спасибо, посмотрю.
Re[3]: Функциональный стиль
От: realloc Россия  
Дата: 28.01.09 19:28
Оценка:
Здравствуйте, DemAS, Вы писали:

DAS>"thesz" <49985@users.rsdn.ru> writes:


>> Были глобальные переменные — стало протягивание состояния.


DAS>Как то это больше на полу-объектно-ориентированное программирование стало

DAS>похоже. Еще структуру заменить на класс, а функции сделать методами класса.

DAS>По теме — может статью Влада про LINQ посмотреть ?


Это http://rsdn.ru/forum/message/3233541.1.aspx?
Посмотрел. По теме не обнаружил ничего. Или я не туда гляжу?
Re[3]: Функциональный стиль
От: thesz Россия http://thesz.livejournal.com
Дата: 28.01.09 20:05
Оценка:
>> Были глобальные переменные — стало протягивание состояния.
DAS>Как то это больше на полу-объектно-ориентированное программирование стало
DAS>похоже. Еще структуру заменить на класс, а функции сделать методами класса.

Тогда получится глобальное состояние в членах класса.

Нам надо, чтобы всё зависело только от входов, менять можно только линейно протягиваемое состояние.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[3]: Функциональный стиль
От: thesz Россия http://thesz.livejournal.com
Дата: 28.01.09 20:15
Оценка:
T>>Были глобальные переменные — стало протягивание состояния.
R>Угу, хорошо. А ещё есть, посложнее?

А что интересует?

Было дело, делал оптимизацию выражений (распространение констант, уменьшение глубины и тп).

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

Типа того:
expr* simplify(expr*a) {
  switch (a->tag) {
    case PLUS:
      expr* l = simplify(a->bin->left);
      expr* r = simplify(a->bin->right);
      if (l->tag == CONST && r->tag == CONST)
        return expr_const(l->constant+r->constant);
      return expr_bin(PLUS,l,r);
    case MINUS: ...
  }
} /* simplify */


В результате вероятность переписать поверх чего-то важного исчезла практически полностью.

По завершению некоторого цикла я копировал в новые арены мои "корни" (важные для меня выражения), а старые переиспользовал.

OCaml, вид в профиль.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[4]: Функциональный стиль
От: realloc Россия  
Дата: 28.01.09 20:35
Оценка:
Здравствуйте, thesz, Вы писали:

T>>>Были глобальные переменные — стало протягивание состояния.

R>>Угу, хорошо. А ещё есть, посложнее?

T>А что интересует?


Всё! Читая про ФП, часто встречал такую мысль: "даже если вы в дальнейшем не будете использовать никакой ФЯ, функциональный стиль окажет сильное влияние на ваш стиль написания программ". Хочется понять на конкретных примерах, как этот самый стиль выливается в конкретные конструкции императивного языка.

T>Было дело, делал оптимизацию выражений (распространение констант, уменьшение глубины и тп).


T>Так я сделал арены, в которых выделялась память и всегда возвращал новое вычисление.


T>Типа того:

T>
T>expr* simplify(expr*a) {
T>  switch (a->tag) {
T>    case PLUS:
T>      expr* l = simplify(a->bin->left);
T>      expr* r = simplify(a->bin->right);
T>      if (l->tag == CONST && r->tag == CONST)
T>        return expr_const(l->constant+r->constant);
T>      return expr_bin(PLUS,l,r);
T>    case MINUS: ...
T>  }
T>} /* simplify */
T>


T>В результате вероятность переписать поверх чего-то важного исчезла практически полностью.


T>По завершению некоторого цикла я копировал в новые арены мои "корни" (важные для меня выражения), а старые переиспользовал.


T>OCaml, вид в профиль.



Э-ээ...., поясни, плиз, вполне процедурный код, имхо. Что здесь функционального?
Re: Функциональный стиль
От: Mr.Cat  
Дата: 28.01.09 21:10
Оценка:
Можете еще этот недавний тред почитать: http://rsdn.ru/forum/message/3248681.1.aspx
Автор: NotGonnaGetUs
Дата: 14.01.09
.
Re[4]: Функциональный стиль
От: ekamaloff Великобритания  
Дата: 28.01.09 21:51
Оценка:
Здравствуйте, realloc, Вы писали:

R>Это http://rsdn.ru/forum/message/3233541.1.aspx?

R>Посмотрел. По теме не обнаружил ничего. Или я не туда гляжу?

Да нет, вот это наверное: http://rsdn.ru//article/?994
Автор(ы): Чистяков Влад (VladD2)
Дата: 26.01.2009
Цель данной статьи – объяснить читателю незнакомому с ФП, что такое функциональный подход, какие он дает преимущества, и как его можно использовать с помощью LINQ и C# 3.0.
Кроме того, эта статья дает некоторое понимание того, как работает «LONQ to Object» и на каких принципах он основан.
. На нее же ссылка на заглавной странице...
... << RSDN@Home 1.2.0 alpha 4 rev. 1138>>
It is always bad to give advices, but you will be never forgiven for a good one.
Oscar Wilde
Re[5]: Функциональный стиль
От: realloc Россия  
Дата: 28.01.09 22:35
Оценка:
Здравствуйте, ekamaloff, Вы писали:

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


R>>Это http://rsdn.ru/forum/message/3233541.1.aspx?

R>>Посмотрел. По теме не обнаружил ничего. Или я не туда гляжу?

E>Да нет, вот это наверное: http://rsdn.ru//article/?994
Автор(ы): Чистяков Влад (VladD2)
Дата: 26.01.2009
Цель данной статьи – объяснить читателю незнакомому с ФП, что такое функциональный подход, какие он дает преимущества, и как его можно использовать с помощью LINQ и C# 3.0.
Кроме того, эта статья дает некоторое понимание того, как работает «LONQ to Object» и на каких принципах он основан.
. На нее же ссылка на заглавной странице...

Упс! Спасибо, теперь вроде оно. Ушёл читать...
Re: Рефакторинг «Повышение Декларативности»
От: Qbit86 Кипр
Дата: 29.01.09 00:58
Оценка: 14 (4)
Здравствуйте, realloc, Вы писали (смайлики скиппед):

R>Как можно использовать subj в императивном языке (меня интересует С, С++)?

R>Если не сложно, приведите примеры небольших кусков кода, реализующих одно и тоже в виде:
R>(ни фига не функционально) ====> (весьма функционально).
R>Спасибо.

Я делаю так.
1) Предпочитаю statement'ам expression'ы.
 a) Стараюсь по возможности вместо if-statement'а использовать if-expression (т. е. тернарный оператор). Недостатком такого подхода является то, что некоторые недалёкие программисты в штыки встречают синтаксис (cond ? expr1 : expr2). Дескать он ухудшает читаемость, и вообще нефиг выпендриваться. Мне же семантика важнее синтаксиса, даже если последний не очень удачен.
Пример перехода от if-statement'а к if-expression'у в C++. Было:
int i = 42;
std::string s("Hello world");
bool condition = true;

if (condition) {
  i = 4;
  s = "Hello";
}
else {
  i = 2;
  s = "world";
}

std::cout << boost::format("(i, s) = (%1%, %2%)") % i % s << std::endl; // (i, s) = (4, Hello)

Стало:
boost::tuples::tie(i, s) =
  (condition ? boost::make_tuple(4, "Hello") : boost::make_tuple(2, "world"));

std::cout << boost::format("(i, s) = (%1%, %2%)") % i % s << std::endl; // (i, s) = (4, Hello)

Возможно, такой код покажется слишком сложным, но это вызвано неуклюжестью языка C++, в ФЯ такой код намного проще.
 b) Предпочитаю вызов функции, возвращающей результат, вместо «процедуры», меняющей аргумент. В случае C# делать рефакторинг «Повышение Декларативности» проще, там ссылочная модель. Так, например, в C++ я не могу просто взять и заменить функцию типа
void Foo(std::vector<int>& v, …);

на функцию
std::vector<int> Foo(…);

потому что return value optimization не гарантируется Стандартом. Приходится либо оборачивать вектор boost::shared_ptr'ом (а то и вовсе использовать boost::shared_array), либо смириться, и передавать его по ссылке. Либо перейти на вменяемый императивный язык ;)

c) В задаче замены statement'ов expression'ами иногда помогает редко используемый оператор запятая. Чаще всего он применяется в инструкции return для превращении цепочки инструкций в выражение. Например, было:
if (something_bad) {
  LogError("Error");
  return false;
}
else {
  return true;
}

Стало:
return (something_bad ? LogError("Error"), false : true);

Ещё на тему оператора запятая поприкалывался Саттер в первом «задачнике», см. пункт 1.18. Mastermind, Решение №2.

2) Если есть возможность писать без внешних состояний (блюсти чистоту), я эту возможность использую. Меньше состояний, меньше глобальных данных, за счёт более частого протаскивания нужных данных в аргументы, и возвращения их из функций вместо модификации. В крайнем случае, можно «запомнить» ссылку на внешние данные в замыкании. В C# это делается с помощью лямбда-выражений, в C++ (ограниченно) с помощь boost::bind. Кроме того, замыкания часто позволяют уменьшить связность в коде (если класс A должен вызывать метод класса B, то не обязательно передавать классу A ссылку на B, можно просто передать классу A анонимную функцию, использующую B, а сам A ничего о B знать не будет).

3) Меньше функций, меняющих состояние каких-то входных данных. Если нужно что-то изменить, лучше вернуть его из функции (как говорилось выше, в C++ такой подход не очень просто сделать эффективным). Грубо говоря, надо стараться минимизировать функции, принимающие параметры по неконстантной ссылке. В C++/C# есть другая проблема — что, если результатом функции должно быть несколько значений? В хороших языках есть встроенные tupl'ы, в C++ есть корявые Boost.Tuples. В C# по-прежнему приходится менять параметры (out/ref), ну или возвращать их упакованными в структуру (самопальный недокортеж).

4) Где только можно использую immutable данные. Вместо модификации данных лучше создавать новые объекты. Т. е. что-то типа такого: вместо
// C#
var c = new MyComplex(2.0, 3.0);
// …
c.Real = 4.0;

сделать MyComplex неизменяемым и при необходимости создавать новый экземпляр:
c = new MyComplex(4.0, c.Imag);


5) Функции высших порядков — очень упрощают рассуждения над программой и её кодирование. К сожалению, в C++98 сейчас не поддерживаются почти никак (boost::function, boost::bind), в C++09 будут поддерживаться кое-как.
Глаза у меня добрые, но рубашка — смирительная!
Re: Функциональный стиль
От: FR  
Дата: 29.01.09 03:19
Оценка:
Здравствуйте, realloc, Вы писали:

R>Как можно использовать subj в императивном языке (меня интересует С, С++)?

R>Если не сложно, приведите примеры небольших кусков кода, реализующих одно и тоже в виде:
R>(ни фига не функционально ) ====> (весьма функционально ).
R>Спасибо .

D'шники сейчас встраивают (в последних версиях уже доступно) функциональщину в очень близкий к
C++ язык, вот тут http://www.digitalmars.com/d/2.0/accu-functional.pdf их взгляд.
Re[3]: Функциональный стиль
От: FR  
Дата: 29.01.09 03:33
Оценка:
Здравствуйте, DemAS, Вы писали:

DAS>Как то это больше на полу-объектно-ориентированное программирование стало

DAS>похоже. Еще структуру заменить на класс, а функции сделать методами класса.

Нет это совсем не похоже на ООП. Там логика практически противоположная.
Я такое протягивание состояния достаточно часто использую, но как-то не думал что
оно функционально, и даже допускал его как легкое нарушение функциональности для
повышения эффективности.
Re[4]: Функциональный стиль
От: DemAS http://demas.me
Дата: 29.01.09 05:52
Оценка:
"thesz" <49985@users.rsdn.ru> writes:

> Тогда получится глобальное состояние в членах класса.


Угу, идею понял.
Posted via RSDN NNTP Server 2.1 beta
Re[2]: Рефакторинг «Повышение Декларативности»
От: Tilir Россия http://tilir.livejournal.com
Дата: 29.01.09 09:08
Оценка: +1 -1 :)
Здравствуйте, Qbit86, Вы писали:

Q>Пример перехода от if-statement'а к if-expression'у в C++. Было:


Через мой code review этот кошмар не прошёл бы. В исходном примере кода следовало бы заменить boost::format на нормальную работу с std::cout чтобы исключить boost из проекта и этим ограничится, остальное там ясно и просто. Вы же вместо этого заменили простой и понятный каждому промышленный код на усложнённый, непонятный для новичка и даже для сениора неудобочитаемый. К тому же гораздо дольше компилируемый. И вероятно к тому же со штрафами на исполнение, хотя тут профайлером надо смотреть, но уж точно не ускорили. В топку такой рефакторинг.
Re[3]: Рефакторинг «Повышение Декларативности»
От: Qbit86 Кипр
Дата: 29.01.09 11:13
Оценка: +1
Здравствуйте, Tilir, Вы писали:

T>Через мой code review этот кошмар не прошёл бы.


Год назад через мой код ревью тоже не прошёл бы.

T>В исходном примере кода следовало бы заменить boost::format на нормальную работу с std::cout


Ссспаде, дался вам здесь Буст. Он в этом примере только как «подстрочный перевод» человеческой записи
Console.WriteLine("(i, s) = ({0}, {1})", i, s);

Синтаксис boost::format'а страшен как смертный грех скорее не из-за разработчиков Буста, а из-за разработчиков C++. Тем не менее, если абстрагироваться от внешнего вида, и сосредоточится на семантике (как в C# выше), то я бы предпочёл вариант с Бустом. Так как он лучше отражает мои намерения, чем какие-то потоки вывода.

T>на нормальную работу с std::cout


Работа с std::cout не может быть нормальной. Уж очень часто приходится прибегать к boost::ios_state_saver для сохранения состояния потока in a RAII-manner.

T>чтобы исключить boost из проекта и этим ограничится


А зачем его исключать из проекта? Он сокращает время разработки и увеличивает свободное время разработчика. Я своё время ценю.

T>Вы же вместо этого заменили простой и понятный каждому промышленный код на усложнённый, непонятный для новичка и даже для сениора неудобочитаемый.


Во-первых, такое усложнение происходит редко, как правило, нужно менять по условию только одну переменную, так что обходится без кортежей в 99% случаев. Во-вторых, семантически этот код прост и ясно выражает мои намеренья, а его синтаксическая сложность вызвана только ущербностью C++. В том же Питоне работа с туплами не намного отличается от работы с одиночными переменными, код единообразен и прост. Т. е. в этом случае не «код усложнённый», а синтаксис усложнённый. Моей вины в том нет.

Про «непонятный для новичка». Моим коллегам такой код был бы понятен. Пойми, мне важно получать кайф от работы. Тратить треть суток на «перебирание гречки» для меня неприемлемо. Я скорее найду другую работу, чем продолжу тянуть лямку в том месте, где сеньоры из-за своей костности и инертности настаивают на снижении качества кода для понимания новичками, вместо подтягивания самих новичков.

T>К тому же гораздо дольше компилируемый.


C++ вообще долгокомпилируемый язык.

T>И вероятно к тому же со штрафами на исполнение, хотя тут профайлером надо смотреть, но уж точно не ускорили.


Об этом я подумаю в самую последнюю очередь. Прежде всего я буду оптимизировать свой труд, и если компилятор плохо справляется со своим (оптимизация), тогда уже буду помогать компилятору. Ну, или сменю язык (как и сделал год назад).
Глаза у меня добрые, но рубашка — смирительная!
Re[5]: Функциональный стиль
От: Mirrorer  
Дата: 29.01.09 12:22
Оценка:
Здравствуйте, realloc, Вы писали:

R>Всё! Читая про ФП, часто встречал такую мысль: "даже если вы в дальнейшем не будете использовать никакой ФЯ, функциональный стиль окажет сильное влияние на ваш стиль написания программ". Хочется понять на конкретных примерах, как этот самый стиль выливается в конкретные конструкции императивного языка.


Тут какой вопрос. Взгляды на мир менять придется. Код-то по прежнему будет написан на императивном языке. И показав этот код, человеку, незнакомому с ФП, можно будет услышать что это красиво написанный код. А человек который знаком с ФП может сказать, ага, это же XXX из Haskell, вид сбоку. А смотреть будут на один и тот же код.
Re: Функциональный стиль
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.09 13:24
Оценка:
Здравствуйте, realloc, Вы писали:

R>Как можно использовать subj в императивном языке (меня интересует С, С++)?

R>Если не сложно, приведите примеры небольших кусков кода, реализующих одно и тоже в виде:
R>(ни фига не функционально ) ====> (весьма функционально ).
R>Спасибо .

Я сделаю проще. Дам тебе два ключевых слова по которым можно будет найти примеры в Гугле:
STL, boost

Поддержка функционального стиля в С++ очень плохая, но хоть что-то...
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Рефакторинг «Повышение Декларативности»
От: Mamut Швеция http://dmitriid.com
Дата: 29.01.09 14:47
Оценка:
Q>Ссспаде, дался вам здесь Буст. Он в этом примере только как «подстрочный перевод» человеческой записи
Q>
Q>Console.WriteLine("(i, s) = ({0}, {1})", i, s);
Q>

Q>Синтаксис boost::format'а страшен как смертный грех скорее не из-за разработчиков Буста, а из-за разработчиков C++.

На самом деле вряд ли что-то мешало разработчиком буста сделать не это:
boost::format("(i, s) = (%1%, %2%)") % i % s


а это:
boost::format("(i, s) = ({1}, {2})", i, s)


Потому что их вариант что-то уж очень страшен
... << RSDN@Home 1.2.0 alpha 4 rev. 1136>>


dmitriid.comGitHubLinkedIn
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.