Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Holy Wars > Erlang vs Haskel


Автор: JoeUser 18.12.15, 16:39
Всем добрейшего времени суток!

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

1) по каким критериям можно сравнить два функциональных языка, например, этих сабжевых?
2) ваши работающие проекты на функциональных языках? кратко и с аргументами почему не на васике писали?

И еще попрошу прокомментировать цитату из вики об Erlang'е:

Цитата
Сравнение Erlang и C++ по производительности

Хотя опытные Erlang-программисты давно заметили, что их программы для тех же задач получаются более краткими по сравнению с другими широко используемыми в промышленности языками программирования, эмпирическое исследование показало, что для изученных телекоммуникационных приложений код на Erlang был на 70-85 % короче, чем на С++, а производительность системы при переписывании кода с С++ на Erlang возросла почти на 100 %. Для одного из использованных в исследовании проектов разница была объяснена написанием дополнительного С++-кода в рамках защитного программирования, управления памятью и кода для высокоуровневой коммуникации, то есть возможностями, которые являются частью языка Erlang и библиотек OTP.


Что-то мне подсказывает, что сравнение взяли из нынешних украинских СМИ ... не? :-? Как можно на языке низкого уровня (у Цэ++ есть все необходимое, чтобы уйти в голый Цэ) не смочь написать программу более быструю, или сравнимую, с той, которую написали на ЯП более высокого уровня? :fool:

Автор: shm 18.12.15, 22:14
Цитата JoeUser @
Что-то мне подсказывает, что сравнение взяли из нынешних украинских СМИ ... не?

Не, ну может на какой-то особенной архитектуре так и будет, а в целом бред конечно.

Автор: D_KEY 18.12.15, 23:43
Почему сразу бред? Если просто в лоб решать какую-то задачу, то вполне может так случиться. Самым правильным тут будет поверить самому.

Автор: Qraizer 19.12.15, 01:28
Проверить, D_KEY?

Автор: JoeUser 19.12.15, 07:56
Скрытый текст
Цитата shm @
Не, ну может на какой-то особенной архитектуре так и будет, а в целом бред конечно.

Да и архитектура тут не при чем, имхо! По определению ЯП более низкого уровня предполагает необходимость больших усилий (размер кода) в угоду больших возможностей построения программных конструкций. Иными словами, на ЯП более низкого уровня можно сделать все то, что делалось на ЯП более высокого уровня (конечно с большими усилиями) ... + иные реализации, которые недоступны на ЯП более высокого уровня. И с помощью которых можно урвать профит и по скорости, и по размеру кода.

Я считаю цитату из вики, которая выше по тексту, полным бредом!

Ждем "функциональщиков" ... :)

Автор: D_KEY 19.12.15, 08:51
Цитата Qraizer @
Проверить, D_KEY?

:D конечно

Автор: Oleg2004 19.12.15, 08:53
Цитата JoeUser @
для изученных телекоммуникационных приложений код на Erlang был на 70-85 % короче, чем на С++, а производительность системы при переписывании кода с С++ на Erlang возросла почти на 100 %.

Интересный раздел программирования появился - телекоммуникационные приложения... :huh:
А что это? Хоть пару примерчиков в общепринятых терминах человеческого понимания?

Автор: D_KEY 19.12.15, 08:56
Цитата JoeUser @
ждем "функциональщиков" ... :)

А чего их ждать-то? Для начала можно взять простенькую задачу, решение в лоб на C++и на haskell/ocaml/erlang и сделать соответствующие измерения.

Я видел, как решение в лоб на C++ было быстрее кучи ручной работы на си. Тоже касается и C и ассемблера. Почему бы и тут этому не сработать?

Автор: shm 19.12.15, 11:54
Цитата D_KEY @
Если просто в лоб решать какую-то задачу, то вполне может так случиться.

Не не не. Фраза звучит так, что как будто на Си++ нельзя написать быстрее. Конечно, если сравнивать с кривым кодом на Си, то можно получить любые результаты, хоть 100000%. Непонятен только смысл этих сравнений.

Добавлено
Цитата JoeUser @
Да и архитектура тут не при чем, имхо!

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

Автор: Qraizer 19.12.15, 13:21
Лично меня смутило вот это:
Цитата
...разница была объяснена написанием дополнительного С++-кода в рамках защитного программирования, управления памятью и кода для высокоуровневой коммуникации...
Легко привести примеры, когда эти факторы приводят к пессимизации кода.

Автор: JoeUser 19.12.15, 13:27
Цитата shm @
функциональные языки будут "ближе"

Ну так фишка в том, что "ближе" - это удобство программирования, а не возможности. Если бы шла речь о количестве функционала в единицу времени - тогда да, чем выше уровень ЯП, тем быстрее разработка. Но речь же шла о производительности кода. Абсурд.

Автор: shm 19.12.15, 14:28
JoeUser, я о архитектуре вычислительной машины.

Автор: JoeUser 19.12.15, 15:22
Цитата shm @
JoeUser, я о архитектуре вычислительной машины.

Без разницы. На низкоуровневом ЯП можно сделать все тоже самое (т.е. не хуже), что и на высокоуровневом. А можно и лучше. На любой архитектуре.

Автор: Oleg2004 19.12.15, 18:54
Цитата shm @
Не, ну чисто теоретически можно придать экзотическую архитектуру, для которой функциональные языки будут "ближе".

Истории известны такие специфические архитектуры машин, например ЛИСП-машина, Пролог-машина. Тупиковая ветвь архитектуры, как например PASDEC - японская машина, для которой Паскаль был родным машинным языком.

Автор: D_KEY 19.12.15, 19:41
Давайте уже задачки решать, что попусту разговоры разговаривать? :)

Добавлено
А то на словах все такие уверенные... :D

Автор: JoeUser 19.12.15, 20:20
Цитата D_KEY @
Давайте уже задачки решать, что попусту разговоры разговаривать?

Функциональщиков бы заманить малеха ... :lol:

Автор: D_KEY 19.12.15, 20:22
Ну korvin, думаю, сможет что-нибудь продемонстрировать. Я попробую(ocaml, haskell), но не уверен, что мой код будет аутентичен.

Автор: Oleg2004 19.12.15, 20:53
Цитата D_KEY @
Я попробую(ocaml, haskell), но не уверен, что мой код будет аутентичен.

Код предназначен для реализации некоего алгоритма - т.е. цепочки действий, исполнение которых в указанном порядке приведет к желаемому результату.
Поэтому для любого кода первична постановка задачи - и описание предполагаемого решения ее с помощью этого кода.
Так что начните с идеи - please :)

Автор: D_KEY 19.12.15, 21:41
Так давайте какую-нибудь задачку придумаем :-?

Автор: Oleg2004 19.12.15, 21:47
В голову приходит только вычисление суммы ряда или поиск максимально-минимального в массиве... :) на худой конец транспонирование матрицы. :(

Автор: D_KEY 19.12.15, 22:12
Вообще в стартовом сообщение речь несколько о других задачах=) В литературе по Erlang'у попадаются примеры историй, когда переписывание на Erlang дало не только выигрыш в объеме кода и стоимости поддержки, но и в производительности. Благодаря erlang'овской модели многопоточности, в основном. И я не вижу в этом ничего необычного.

Автор: Oleg2004 19.12.15, 22:23
Я с вами согласен. И в самом первом своем посте я как раз обратил внимание собеседников на вот это:
Цитата
что для изученных телекоммуникационных приложений код на Erlang был на 70-85 % короче, чем на С++, а производительность системы при переписывании кода с С++ на Erlang возросла почти на 100 %.

и спросил - а ЧТО ЭТО???
что такое - телекоммуникационное приложение? :wall: где Erlang превыше всех???
Дальнейшее - молчание. (с) Гамлет <_<

Автор: D_KEY 19.12.15, 22:26
Цитата
Erlang [ˈɜːlæŋ][2] — функциональный язык программирования со строгой динамической типизацией, предназначенный для создания распределённых вычислительных систем. Разработан и поддерживается компанией Ericsson. Язык включает в себя средства порождения параллельных легковесных процессов и их взаимодействия через обмен асинхронными сообщениями в соответствии с моделью акторов.

Erlang был целенаправленно разработан для применения в распределённых, отказоустойчивых, параллельных системах реального времени[⇨], для которых кроме средств самого языка имеется стандартная библиотека модулей[⇨] и библиотека шаблонных решений (так называемых поведений) — фреймворк OTP (англ. Open Telecom Platform)[⇨]. Программа на Erlang транслируется в байт-код, исполняемый виртуальными машинами, находящимися на различных узлах распределённой[⇨] вычислительной сети. Erlang-системы поддерживают горячую замену кода[⇨], что позволяет эксплуатировать оборудование безостановочно.

Свой синтаксис и некоторые концепции Erlang унаследовал от языка логического программирования Пролог[3]. Язык поддерживает многие типы данных[⇨], условные конструкции[⇨], сопоставление с образцом[⇨], обработку исключений[⇨], списковые включения[⇨] и выражения битовых строк[⇨], функции[⇨] (анонимные функции[⇨], функции высшего порядка, рекурсивные определения функций, оптимизацию хвостовой рекурсии), модули[⇨], приём и отправку сообщений[⇨] между процессами. Препроцессор[⇨] поддерживает работу с макросами и включение заголовочных файлов.

Популярность Erlang начала расти в связи с расширением его области применения (телекоммуникационные системы) на высоконагруженные параллельные распределённые системы, обслуживающие миллионы пользователей WWW, такие как чаты, системы управления содержимым, веб-серверы и распределённые, требующие масштабирования базы данных. Erlang применяется в нескольких NoSQL-базах данных высокой доступности[4].


Добавлено
И как заточенный под конкретное применение инструмент, он вполне может быть лучше решения, написанного на языке общего назначения. Естественно, что приложив определенные усилия, можно сделать лучшее решение на C++. Просто это дополнительное время и дополнительные деньги(или заранее заложенные в проект требования, что тоже не бесплатно).

Добавлено
Цитата Oleg2004 @
что такое - телекоммуникационное приложение? :wall: где Erlang превыше всех???

Ну гугл же есть. Вот, например:
Цитата
Под телекоммуникационными системами (ТС) принято понимать структуры и средства, предназначенные для передачи больших объёмов информации (как правило, в цифровой форме) посредством специально проложенных линий связи или радиоэфира. При этом предполагается обслуживание значительного количества пользователей систем (от нескольких тысяч). Телекоммуникационные системы включают такие структуры передачи информации, как телевещание (коллективное, кабельное, спутниковое, сотовое), телефонные сети общего пользования (ТфОП), сотовые системы связи (в том числе макро- и микро- сотовые), системы персонального вызова, спутниковые системы связи и навигационное оборудование, волоконные сети передачи информации.

Автор: Oleg2004 19.12.15, 22:36
Спасибо.
Хорошая выборка основных понятий и процессов.
Основное резюме - что я посчитал важным - это семантическая сеть, покрывающая свои требования по реализации за счет распределенной сети виртуальных узлов с центром (или центрами?) управления.
Фактически это распределенная задача по обработке текстовой информации самых разных форматов.
Естественно, что задачка про Хелло ворлд тут рядом не лежала. :D

Добавлено
Ну и под занавес.
Я достаточно долго работаю в области теории и практики компиляции языков высокого уровня.
И знаком со многими языками программирования.
И мое глубочайшее убеждение - КАЖДЫЙ современный язык имеет свою собственную нишу применения. Классификаций языков программирования - вагон и малая тележка. Языки в подавляющем большинстве создаются не для того, чтобы конкурировать - а для того, чтобы закрывать новые потребности. Возникают новые парадигмы, новые задачи, и под них создаются конкретные языки программирования. А потому такие сравнения, типа С++ vs Erlang - неправомерны и ущербны в своей сути. ИМХО. :)
Простой пример - ну как можно сравнить XML и С++??? :wall:
Или HTML и С++?? А ведь и HTML, и XML - это языки, имеющие огромное значение в телекоммуникационном (т.е. по простому - в удаленном) взаимодействии.

Добавлено
Цитата D_KEY @
Естественно, что приложив определенные усилия, можно сделать лучшее решение на C++.

И тут вы правы.
В свое время лет 35 тому назад у меня был коллега, высококлассный программист, который знал только один язык - Фортран. Он мне как то сказал - я на этом языке могу написать программу для любой задачи. Любой.
Он был прав. По своему. Но Фортран - не предназначен для текстовой обработки. И такая программа была бы просто уродлива скорее всего.

Автор: Qraizer 20.12.15, 01:50
Цитата D_KEY @
Так давайте какую-нибудь задачку придумаем
Какой-нибудь микросимулятор Ютуба подойдёт?

Автор: D_KEY 20.12.15, 12:36
Цитата Qraizer @
Цитата D_KEY @
Так давайте какую-нибудь задачку придумаем
Какой-нибудь микросимулятор Ютуба подойдёт?

Возможно, только расскажи подробнее, что имеешь в виду :)

Автор: Oleg2004 20.12.15, 13:39
Вот здесь приводится ерланговский код для задачи о перестановках. В конце комментов приводится сишный код для той же задачи - вполне конкурентный с ерланговским. И читается вполне удобно и понятно. :)
И вот еще интересные откровения разрабоотчиков с Яндекса - какой язык кто и за что любит и работает на нем. Прочитал с удовольствием.
Нашел и такое откровение:
Цитата
Мой мимолетный опыт с функциональщиной (oCaml) закончился этим: невменяемость и ахинея. Я принимаю, что это могут быть лично мои заморочки, либо мои императивные боги сильно против языколожства.
:)
Там же на Яндексе:
Цитата
Но в будущем все будут писать на Rust. Rust — это моя любимая тема. Я всем рассказываю про Rust. Проблема C++ в том, что хотя программы получаются быстрыми, но написать их на нём так, чтобы они не падали, очень тяжело. Язык дает очень мало гарантий безопасности. Java дает очень много гарантий, но не позволяет писать программы так, чтобы они быстро работали. Rust, с одной стороны, позволяет писать безопасные программы, с другой — очень быстрые. Поэтому мой любимый язык программирования — это Rust. Но он еще не дошел до такого состояния, чтобы его можно было использовать, и будет таким лет через пять.

Вот это для меня открытие...все переходим на RUST... а что это за зверь?
Не знаю, надо смотреть.
Вот обсуждение на Gamedev
Приводится код TCP-сервера на Эрланге. Все существенно сложнее чем на С++.
Очень понравился луркморный обзор Эрланга :)

Автор: Qraizer 20.12.15, 15:21
Oleg2004, Степан Кольцов неверно выразился. Проблема C++ не в том, что на нём тяжело писать непадучие программы, а в том, что на нём можно писать программы, сделать которые непадучими тяжело. Однако вполне можно игнорировать эту фичу, но это требует знаний и опыта.

Добавлено
D_KEY, ну например, имея несколько, можно много, источников данных, например, файлов, по запросам отдавать их контент. Запросы могут приходить к разным источникам данных, а могут и к одному, контент запрашиваться из разных регионов источников, например, по разным смещениям от начала файлов, активных запросов может быть несколько в одно время, запросы на данные из некоего источника среднестатически запрашивают их последовательно расположенными порциями со среднестатически одинаковой периодичностью, но это не всегда так.
Короче, тут больше над кодом клиента надо работать для получения объективных оценок кода сервера.

Автор: Oleg2004 20.12.15, 17:41
Кто пояснит, что означает такая конструкция на Эрланге - а точнее что означают три точки - и как их набрать на клаве? :wacko:
∴ x = 5
Цитата Qraizer @
а в том, что на нём можно писать программы, сделать которые непадучими тяжело.

Если идти эрланговским путем и сделать для исполнения кода С++ некую виртуальную оболочку типа VM или фреймворка, упаковать это все в одно целое - то почему нет? Именно это обстоятельство и дает Эрланговским узлам такое преимущество.
Просто для приложений С++ этого не надо.
У него совсем другая ниша.
Хватает того, что все сокетные операции в эрланг-модулях gen_tcp, gen_udp, gen_sctp
сделаны на С++(для стека TCP/IP другого программного интерфейса, кроме сокетов Беркли и их клона Winsоck)просто нет.
А если честно говорить, я сегодня впервые почитал про Эрланг и идеологию его исполнения, и пришел к мнению, что для определенных видов сетевых приложений это неплохая штука. :yes:
И да, таки я оказался прав в своем представлении:
Цитата
Мое первое знакомство с Erlang состоялось в июле 2012-го, но зарабатывать программированием на этом языке я начал только год назад, 19 ноября 2012. В сей заметке я хотел бы поделиться своими впечатлениями от практического использования Erlang на протяжении всего этого времени. Erlang — не функциональный, а скорее объектно-ориентированный, и вовсе не язык программирования, а фреймворк для создания распределенных отказоустойчивых приложений. Ну или не очень отказоустойчивых и не очень распределенных, тут уж как напишите. Почему фреймворк — понятно, вся мощь Erlang’а заключается в Open Telecom Platform, включающей в себя поведения gen_server, gen_event и другие, а также ETS, Mnesia и так далее.

Спасибо ТС за тему, она была для меня полезной.
Так что для меня после ознакомления со всеми делами вопрос закрыт... :)

Автор: korvin 21.12.15, 17:38
Цитата Oleg2004 @
∴ x = 5

А откуда ты это взял? Ни разу не встречался с таким символом. И гугл ничего не говорит.



Что же касается темы. В Эрланге функциональщины почти столько же, сколько и в Си. Ну или в джава-скрипте. Как его сравнивать с Хаскеллом?

Автор: Славян 21.12.15, 17:49
Цитата Oleg2004 @
как их набрать на клаве?
Alt+8756 на цифровой. :)

Автор: korvin 21.12.15, 17:51
Цитата JoeUser @
1) по каким критериям можно сравнить два функциональных языка, например, этих сабжевых?

Например:
- "ленивый" (Haskell, Clean, Miranda) или "энергичный" (*ML, F#, Scala, Clojure, Scheme)
- чистый (т.е. строго и явно разделяющий чистые и грязные функции. Haskell, Clean, Miranda) или допускающий свободное использование побочных эффектов и других парадигм (*ML, F#, Scala, Clojure, Scheme)
- статически типизированный (Haskell, Clean, Miranda, *ML, F#, Scala) или динамически-типизированный (Clojure, Scheme)

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

Автор: MyNameIsIgor 21.12.15, 18:15
Цитата korvin @
В Эрланге функциональщины почти столько же, сколько и в Си.

:wacko:

Автор: JoeUser 21.12.15, 18:16
Цитата korvin @
А вообще, похоже, тебе эта тема на самом деле совсем не интересна, иначе ты потрудился бы ознакомиться с предметом чуть более глубже, чем "а я вот тут в рукипедии прочитал такую фигню и нифига не понимаю".

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

Цитата korvin @
Например:

Я это прочел, как "наиболее значимые" (ну, которые в области внимания). Не будешь же ты специально приводить незначимые? ;)

А вообще, попутно выяснял для себя еще один вопрос. Многие прямым текстом пишут "Перл - птичий язык". До селе не мог понять причину. Что не так? Сейчас ситуация немножко прояснилась. Для меня что Эрланг, что Хаскель - тоже птичьи. А причина, скорое всего, не в самом синтаксисе. Причина в отсутствии понимания (+отсутствия практики применения) концепций языка, возможностей, "вкусностей".

Так что, твой комент был не лишним, и сэкономил мне немножко времени. Пасип :rolleyes:

Автор: Oleg2004 21.12.15, 18:35
Цитата korvin @
Цитата Oleg2004 @ Вчера, 19:41
∴ x = 5
А откуда ты это взял? Ни разу не встречался с таким символом. И гугл ничего не говорит.

Блин, еле раскопал ссылку где я это видел
Там таких знаков хватает. <_<

Автор: MyNameIsIgor 21.12.15, 18:41
Цитата Oleg2004 @
Цитата korvin @
Цитата Oleg2004 @ Вчера, 19:41
∴ x = 5
А откуда ты это взял? Ни разу не встречался с таким символом. И гугл ничего не говорит.

Блин, еле раскопал ссылку где я это видел
Там таких знаков хватает. <_<

Ну, очевидно же, что к языку этот знак не относится. Он означает что-то вроде "вывод на консоль".

Автор: Oleg2004 21.12.15, 18:48
Цитата MyNameIsIgor @
Ну, очевидно же, что к языку этот знак не относится. Он означает что-то вроде "вывод на консоль".

Для меня совсем не очевидно.
В легальном коде стоит некий знак - ну типа стрелка, или :=.
Очевиднее, что эта комбинация легальна...тем более что она пишется как само собой разумеющееся, обыденное, без расшифровки.
И в первых абзацах ВВЕДЕНИЯ!!!
Те более что в такой записи это на вывод вообще не тянет
∴ 5 = 6

Впрочем теперь понимание этого знака для меня неактуально.
Хотя история его возникновения интересна сама по себе. :)

Автор: korvin 21.12.15, 18:57
Цитата Oleg2004 @
Для меня совсем не очевидно.
В легальном коде стоит некий знак - ну типа стрелка, или :=.
Очевиднее, что эта комбинация легальна...тем более что она пишется как само собой разумеющееся, обыденное, без расшифровки.
Впрочем теперь понимание этого знака для меня неактуально.
Хотя история его возникновения интересна сама по себе.

Я конечно понимаю, что 5 = 6 или 2009/10/22 = 2009/10/23 -- вполне легальные конструкции, но всё-таки Игорь прав, из листингов вполне очевидно, что выражения, помеченные этим знаком, не являются строками из исходников. Как будто ты никогда шелл prompt $ никогда не видел?

Добавлено
Цитата MyNameIsIgor @
:wacko:

Ну а что? Не так уж сильно далеко от Си Эрланг ушёл в этом плане. Подумаешь, TCO есть... =)

Автор: Oleg2004 21.12.15, 19:04
На шелловскую команду тоже не тянет :D
Какой обалдуй будет писать такой символ, который на клаве не набрать одной клавишей :lool:
И да, гугля молчит о нем как рыба об лед. :(

Автор: MyNameIsIgor 21.12.15, 19:08
Цитата korvin @
Цитата MyNameIsIgor @
:wacko:

Ну а что? Не так уж сильно далеко от Си Эрланг ушёл в этом плане. Подумаешь, TCO есть... =)

Не понимаю, почему недалеко. Все языки с вызовом по значению недалеко ушли?

Автор: korvin 21.12.15, 19:10
Цитата Oleg2004 @
На шелловскую команду тоже не тянет :D

Это и не шелловская команда.

Цитата Oleg2004 @
Какой обалдуй будет писать такой символ, который на клаве не набрать одной клавишей :lool:

Такой, который хочет показать, что это спец-символ и не принадлежит языку, а обозначает что-то другое. А то некоторые вот путают...
Скажи, а если б там символ > стоял вместо этого, что бы ты подумал?

Цитата Oleg2004 @
И да, гугля молчит о нем как рыба об лед.

У тебя пиратский гугл.
https://en.wikipedia.org/wiki/Therefore_sign
https://www.quora.com/Punctuation/What-does...-mean-%E2%88%B4

Добавлено
Цитата MyNameIsIgor @
Все языки с вызовом по значению недалеко ушли?

Нет. Но Эрланг не совсем в сторону функциональщины двигался же.

Автор: MyNameIsIgor 21.12.15, 19:15
Цитата korvin @
Нет. Но Эрланг не совсем в сторону функциональщины двигался же.

А куда он двигался? Что тебя смущает? Отсутствие монад?

Автор: Oleg2004 21.12.15, 19:16
Цитата korvin @
У тебя пиратский гугл.

Спасибо за наводку :yes:
+1.

Автор: korvin 21.12.15, 19:26
Цитата MyNameIsIgor @
А куда он двигался? Что тебя смущает? Отсутствие монад?

В concurrency. А меня ничего не смущает. =) Ну, кроме того, что конкурентные процессы не чисты by-design.

Автор: MyNameIsIgor 21.12.15, 19:32
Цитата korvin @
Цитата MyNameIsIgor @
А куда он двигался? Что тебя смущает? Отсутствие монад?

В concurrency. А меня ничего не смущает. =)

Ну, он же лишён деструктивных присваиваний. Да, функции, влияющие на глобальное окружение не отделены, потому исполняется всё последовательно. Но это явно не C.

Добавлено
Цитата korvin @
Ну, кроме того, что конкурентные процессы не чисты by-design.

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

Автор: korvin 21.12.15, 19:43
Цитата MyNameIsIgor @
Ну, он же лишён деструктивных присваиваний. Да, функции, влияющие на глобальное окружение не отделены, потому исполняется всё последовательно. Но это явно не C.

А кто запрещает не использовать деструктивные присваивания в Си? Но дело не в этом.

Цитата MyNameIsIgor @
Из этого следует, что любой язык, дающий возможность программисту управлять конкурентными процессами, а не делающий это автоматически, недалеко ушёл от C в части функциональщины

Нет, из этого лишь следует, что в Эрланге внимание акцентировано на другом, а в сторону функциональщины он сделал лишь пару небольших шагов от Си.

Автор: MyNameIsIgor 21.12.15, 19:44
Цитата korvin @
в сторону функциональщины он сделал лишь пару небольших шагов от Си

Есть какие-то объективные мерки?

Автор: D_KEY 21.12.15, 21:55
Цитата korvin @
а в сторону функциональщины он сделал лишь пару небольших шагов от Си.

Есть мнение, что они шли не от Си :)
Я тоже не понимаю, чем тебе erlang не угодил...

Добавлено
Цитата Qraizer @
D_KEY, ну например, имея несколько, можно много, источников данных, например, файлов, по запросам отдавать их контент. Запросы могут приходить к разным источникам данных, а могут и к одному, контент запрашиваться из разных регионов источников, например, по разным смещениям от начала файлов, активных запросов может быть несколько в одно время, запросы на данные из некоего источника среднестатически запрашивают их последовательно расположенными порциями со среднестатически одинаковой периодичностью, но это не всегда так.
Короче, тут больше над кодом клиента надо работать для получения объективных оценок кода сервера.

Можно, в принципе, попробовать. Правда если внимательно посмотреть на тему, то придется сравнивать erlang и haskell :)

korvin, ты как?

Добавлено
Цитата MyNameIsIgor @
Цитата korvin @
Нет. Но Эрланг не совсем в сторону функциональщины двигался же.

А куда он двигался? Что тебя смущает? Отсутствие монад?

Монады-то можно и прикрутить. Даже в C++ я препятствий не вижу к этому. Вот do-нотацию заменить сложнее :)

Автор: MyNameIsIgor 21.12.15, 22:54
Цитата D_KEY @
Монады-то можно и прикрутить. Даже в C++ я препятствий не вижу к этому.

Смысл монады не в интерфейсе, а в абстракции побочных эффектов. Хотя в C++ был бы полезен и интерфейс для, например, future.
Цитата D_KEY @
Вот do-нотацию заменить сложнее

Так код на Erlang сам по себе и есть do-нотация :yes: korvin подтвердит.

Автор: D_KEY 22.12.15, 08:09
Цитата MyNameIsIgor @
Смысл монады не в интерфейсе, а в абстракции побочных эффектов.

Ну скорее в абстракции цепочки вычислений или даже абстракции связей в цепочке вычислений. Побочные эффекты есть не у всех монад, вроде даже большая часть вполне чистые. Да и IO "грязь" скрывает через RealWorld, т.е. строится через RealWorld -> (RealWorld, a).

Впрочем, я, возможно, так и не понял монады, хотя вроде разобрался, как это дело работает :D
С технической точки зрения там как-то все неэффективно выходит. Надо будет глянуть, оптимизирует ли их тот же ghc.

Автор: JoeUser 22.12.15, 10:51
Нашел небольшой мануал по Хаскелю. Без пал-литры не разбересся! :wacko:

Цитата D_KEY @
Побочные эффекты есть не у всех монад,

Прочел по монады ... по верхам все вроде ясно. Но в фундаментальных вопросах (скорее в терминологии) плыву :-?
Вопрос: функция, использующая функцию с побочными эффектами, имеет побочные эффекты (если все остальное - чистые вычисления)? Ну или класс, один из методов которого имеет побочные эффекты?

Добавлено
Еще пробежался по мануалу Эрланга. Похоже korvin таки прав, Эрланг - в большей части декларативный язык, нежели функциональный. Не знаю как вам, мне показался более понятным по концепции. Сопоставления по образцу вообще порадовали - в духе регулярок Перла, правда с несколько другим применением. А вот однократное присваивание значений сразу приводит к мысли ожидаемой излишней траты памяти. Ну это так, по верхам.

Автор: D_KEY 22.12.15, 11:33
Цитата JoeUser @
Вопрос: функция, использующая функцию с побочными эффектами, имеет побочные эффекты (если все остальное - чистые вычисления)?

Да. В Haskell монада IO "заражает" код. И просто так из монадического вычисления результат не достать. Он доступен только внутри вычисления.

Цитата
Эрланг - в большей части декларативный язык, нежели функциональный.

Эм. Функциональные языки - это декларативные языки. Как, например, и логические.

Цитата
Сопоставления по образцу вообще порадовали

Они есть, наверное, во всех функциональных языках.

Добавлено
Могу попробовать накидать монады + реализацию монады IO на C++, если интересно. Но без do-нотации читать монадические выражения не так просто :)

Автор: JoeUser 22.12.15, 11:51
Цитата D_KEY @
Эм. Функциональные языки - это декларативные языки. Как, например, и логические.

Ну да, эт я плаваю :rolleyes:

Добавлено
Цитата D_KEY @
Могу попробовать накидать монады + реализацию монады IO на C++, если интересно.

Интересно!

Добавлено
Цитата D_KEY @
Как, например, и логические.

Точно! Читал доку по Эрлангу, видел там вычисление функции как последовательность утверждений, де жа вю ... Пролог.

Автор: D_KEY 22.12.15, 12:04
Пока только просто монады, IO потом попробую изобразить.
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    class Monad m where
      (>>=) :: m a -> (a -> m b) -> m b
      (>>) :: m a -> m b -> m b
      return :: a -> m a
      fail :: String -> m a


fail нам не нужен, остальное можно как-то так изобразить:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    template<template<class ...> class M>
    struct Monad {
        // return :: a -> m a
        template<typename T>
        static auto ret(T a) -> M<T>;
     
        // bind :: m a -> (a -> m b) -> m b
        template<typename T, typename U>
        static auto bind(M<T>, std::function<M<U>(T)>) -> M<U>;
    };

Хелперы/операторы:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // return :: a -> m a
    template<template<class...> class M, typename T>
    auto ret(T a) -> M<T>
    {
        return Monad<M>::ret(std::move(a));
    }
     
    // (>>=) :: m a -> (a -> m b) -> m b
    template<template<class...> class M, typename T, typename F>
    auto operator >>= (M<T> ma, F fun) -> decltype(fun(std::declval<T>()))  // запутанно, но не знаю, как сделать лучше, чтобы работали лямбды
    {
        using R = decltype(fun(std::declval<T>()));
        return Monad<M>::bind(ma, std::function<R(T)>(std::move(fun)));
    }
     
    // (>>) :: m a -> m b -> m b
    template<template<class...> class M, typename T, typename U>
    auto operator >> (M<T> ma, M<U> mb) -> M<U>
    {
        return ma >>= [=](T){ return mb; };
    }


Теперь нужно специализировать Monad<обертка>::ret и Monad<обертка>::bind.
Проверяем на простой монаде:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    template<typename T>
    struct value { // просто коробка со значением
        value(T a)
            : x(a)
        {}
     
        T x;
    };
     
    // специализируем ret
    template<>
    template<typename T>
    auto Monad<value>::ret(T a) -> value<T>
    {
        // заворачиваем в коробку
        return value<T>(a);
    }
     
    // специализируем bind
    template<>
    template<typename T, typename U>
    auto Monad<value>::bind(value<T> d, std::function<value<U>(T)> f) -> value<U>
    {
        // достаем значение, вызываем функцию, которая вернет следующую коробку
        return f(d.x);
    }


Проверяем на чем-нибудь простом:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    auto succ(int x) -> value<int>
    {
        return ret<value>(x + 1);
    }
     
    int main()
    {
        auto v = (ret<value>(10) >>= succ) >>= succ;
     
        std::cout << v.x << std::endl;
    }

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    12


Вместо (ret<value>(10) >>= succ) >>= succ хотелось бы писать ret<value>(10) >>= succ >>= succ, но тут у C++ другая ассоциативность >>= чем в haskell. Можно заменить >>= на какой-нибудь другой оператор, на &, например.
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    ret<value>(10) & succ & succ


http://ideone.com/9AHtv1

Автор: JoeUser 22.12.15, 12:21
Цитата D_KEY @
fail нам не нужен, остальное можно как-то так изобразить:

Наверное нужен ;) Я попробовал вместо 10 подставить 10.7f - отработало без ошибок и выдало 12 ... Хм ... подставил строку "abc" - отказалось собираться вообще. Значить fail надо как-то определять. Не?

Автор: D_KEY 22.12.15, 12:33
Цитата JoeUser @
Наверное нужен ;)

Не, fail используется для других ситуаций.

Цитата
Я попробовал вместо 10 подставить 10.7f - отработало без ошибок и выдало 12

Ну так это к неявным преобразованиям в C++ претензии.

Цитата
подставил строку "abc" - отказалось собираться вообще

Так и должно быть.

Автор: JoeUser 22.12.15, 12:42
Цитата D_KEY @
Не, fail используется для других ситуаций.

А каких?

Автор: D_KEY 22.12.15, 12:57
Цитата JoeUser @
Цитата D_KEY @
Не, fail используется для других ситуаций.

А каких?

Он вызывается в случае ошибки сопоставления с образцом внутри монадического вычисления. Ну т.е. когда вы пытаетесь выполнить сопоставления с образцом вот в таком случае:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    do
        ...
        (SomeConstructor x) <- someFun
        ...

а значение не соответствует образцу(в нашем случае someFun вернул значение с другим конструктором), то будет вызыван fail.
Не уверен, что понятно объяснил :)

Добавлено
Монаду IO реализую или вечером или завтра, сейчас надо работу работать :)

Автор: D_KEY 22.12.15, 14:09
Цитата D_KEY @
Вместо (ret<value>(10) >>= succ) >>= succ хотелось бы писать ret<value>(10) >>= succ >>= succ, но тут у C++ другая ассоциативность >>= чем в haskell. Можно заменить >>= на какой-нибудь другой оператор, на &, например.
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    ret<value>(10) & succ & succ

Или на , :D

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    val x = (ret<value>(10), succ, succ, succ, succ);

Автор: JoeUser 22.12.15, 15:44
Цитата D_KEY @
Он вызывается в случае ошибки сопоставления с образцом внутри монадического вычисления.

Покажи, плс, на самом коротеньком примере.

Автор: D_KEY 22.12.15, 16:29
Ну вот простой пример(имей в виду, что return - это не императивный return, а функция, которая, грубо говоря, заворачивает значение в нашу монаду):

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    -- Функция, которая возвращает действие ввода/вывода,
    -- в котором завернут Nothing, явно типизированный как Maybe Int
    fun1 :: IO (Maybe Int)
    fun1 = return (Nothing)
     
    -- функция проверки
    testIO = do
        -- здесь будет вызван fail, т.к. ждем Just, а приходит Nothing:
        (Just x) <- fun1
        print x


В монаде IO fail кидает ошибку. Проверяем:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    main = testIO

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    main: user error (Pattern match failure in do expression...


Теперь возьмем другую монаду, где fail означает не ошибку, а какое-то значение. Тут подойдет список:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    -- делаем тоже самое:
     
    fun2 :: [Maybe Int]
    fun2 = return (Nothing) -- тоже что [Nothing]
     
    -- Проверяем список
    testList = do
        -- здесь будет вызван fail, т.к. ждем Just, а приходит Nothing:
        (Just x) <- fun2
        return (x)


Для списка fail просто возвращает пустой список. Проверяем:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    main = print testList

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    []


Добавлено
Если что, Maybe - это тип, который имеет два конструктора:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    data Maybe a = Just a | Nothing


Соответственно, в наших тестах мы выполняем сопоставление с образцом и ждем конструктор Just, а приходит туда Nothing. В случае монадического вычисления с IO мы получаем ошибку, а для монадического вычисления со списками - пустой список. Поскольку в C++ нет сопоставления с образцом, пользы от fail нет никакой. А понимание монад он никак не проясняет(скорее мешает).

Автор: JoeUser 22.12.15, 17:32
Цитата D_KEY @
Поскольку в C++ нет сопоставления с образцом, пользы от fail нет никакой.

А может ли служить в Цэ++ в качестве "сопоставления с образцом" - std::type_info (в частности std::type_info::before)?
Если конечно я правильно начинаю осознавать реальность :lol:
В случае наследования с использованием RTTI, мы сможем вырвать кусок у объекта на произвольном уровне иерархии (с помощью его конструктора). А вот если нужный нам конструктор отсутствует в иерархии - тогда и нужно выкидывать fail. Кстати, а как его в Цэ++ реализовать, исключение бросить штоле?

Извини, что достаю вопросами. Просто пока не могу распознать ценности всего этого для меня.

Попутно еще одни вопрос. Многие в процессе моделирования используют/манипулируют понятиями Шаблоны Проектирования (ну или Паттерны). И это безотностительно к какому-то конкретному ЯП. Рассматриваемые "монады" какой(или какие совокупности) из паттернов реализуют? И вообще можно ли так говорить относительно монад?

Автор: applegame 22.12.15, 19:34
Да любой код на C++ уже считай монада. Операции идут одна за другой - чем не монада?

Автор: D_KEY 22.12.15, 20:07
Цитата applegame @
Да любой код на C++ уже считай монада. Операции идут одна за другой - чем не монада?

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

Автор: D_KEY 22.12.15, 22:08
Списки тоже монады.
Потому можно написать:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    fun = do
        x <- [1, 2, 3]
        y <- [4, 5, 6]
        return (x, y)
     
    main = print fun

И получить:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]


На самом деле тут использована do-нотация, которая представляет из себя синтаксический сахар. Рассахаривается это в
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    fun =
        [1, 2, 3] >>= \x ->
        [4, 5, 6] >>= \y ->
        return (x, y)


Т.е. так:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    fun =
        [1, 2, 3] >>= (\x ->
            [4, 5, 6] >>= (\y ->
                return (x, y)))


Что на крестах выглядит примерно так:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    auto res = mk_list({1, 2, 3}) >>= [](auto x) {
        return mk_list({4, 5, 6}) >>= [=](auto y) {
            return ret<list>(std::make_pair(x, y));
        };
    };


С тем же результатом:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]


Для этого нужно сделать списки и реализовать для них монаду.
список(на основе вектора)
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    template<typename T>
    struct list : private std::vector<T> {
        using impl = std::vector<T>;
        using impl::value_type;
     
        list() = default;
        list(std::initializer_list<T> il)
            : std::vector<T>(std::move(il))
        {
        }
     
        using impl::push_back;
        using impl::insert;
        using impl::begin;
        using impl::end;
    };
     
    auto mk_list(std::initializer_list<T> il) -> list<T>
    {
        return list<T>(il);
    }


Реализуем монаду для списка:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    template<>
    template<typename T>
    auto Monad<list>::ret(T a) -> list<T>
    {
        // заворачиваем объект в список
        return list<T>{a};
    }
     
    template<>
    template<typename T, typename U>
    auto Monad<list>::bind(list<T> ma, std::function<list<U>(T)> f) -> list<U>
    {
        // формируем список списков путем применения к каждому элементу переданной функции
        // (которая принимает объект, а возвращает монаду(список))
        list<list<U> > tmp;
        std::transform(ma.begin(), ma.end(), std::back_inserter(tmp), f);
     
        // конкатенируем списки в один
        list<U> res;
        for (auto & v : tmp) {
            res.insert(res.end(), v.begin(), v.end());
        }
        return res;
    }


Ну и для вывода пара вспомогательных функций:
вывод пар и списков
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    template<typename T, typename U>
    std::ostream & operator << (std::ostream & os, std::pair<T,U> p)
    {
        os << "(" << p.first << "," << p.second << ")";
        return os;
    }
     
    template<typename T>
    std::ostream & operator << (std::ostream & os, const list<T> & a)
    {
        os << "[";
        int i = 0;
        for (auto & e : a) {
            if (i++) os << ",";
            os << e;
        }
        os << "]";
        return os;
    }


http://ideone.com/bJjEW3

Автор: D_KEY 23.12.15, 09:55
Теперь по поводу IO.

Смысл IO в добавлении работы с побочными эффектами в чистый язык. Одним из способов(в каком-то смысле теоретическим) представления побочных эффектов в чистом языке является работа с некоторым объектом, представляющим "реальный мир".

И каждое действие с побочными эффектами в чистом языке мы будем представлять в виде функций вида (real_world) -> (real_world, data). Т.е. мы как будто не меняем внешние условия, а возвращаем новое состояние мира вместе с каким-то значением.
IO<T> как раз представляет собой обертку над (real_world) -> (real_world, T) и позволяет через монадический интерфейс работать с вычислениями, "меняющими мир"(через якобы возврат "нового мира").

В Haskell тип RealWorld скрыт от пользователя, как и внутренняя структура IO, т.е. наружу торчит только тип IO a, но запаковываем значение мы через return, а достаем значение только внутри монадического вычисления(как и в других монадах - через лямбду или <- в do-нотации).

Теперь возвращаемся к C++.
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    struct real_world
    {
        explicit real_world(size_t i = 0) : m_i(i) {}
     
        real_world(const real_world &) = delete;
        real_world(real_world && other) : m_i(other.m_i) {}
     
        const real_world & operator = (const real_world & other) = delete;
        const real_world & operator = (real_world && other) = delete;
     
        // "меняем мир"
        // принимаем функцию с побочными эффектами,
        // возвращаем пару из "нового мира" и результата функции
        template<typename T, typename F>
        std::pair<real_world, T> change(F f) const
        {
            return std::make_pair(real_world{m_i + 1}, f());
        }
     
    private:
        const size_t m_i;
    };


IO:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    template<typename T>
    struct IO {
       // инкапсулируем функцию, маскирующую побочные эффекты через возврат "нового мира"
        using f_type = std::function<std::pair<real_world, T>(real_world)>;
     
        explicit IO(f_type f)
            : m_f(std::move(f))
        {
        }
     
        // запускаем функцию, которая порождает "новый мир" и значение
        auto run(real_world w) const -> std::pair<real_world, T>
        {
            return m_f(std::move(w));
        }
     
    private:
        f_type m_f;
    };


Реализуем монаду:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    template<>
    template<typename T>
    auto Monad<IO>::ret(T a) -> IO<T>
    {
        // создаем IO с функцией, которая просто создает пару из "мира" и значения,
        // не производя побочных вычислений и не меняя мир
        return IO<T>([=](real_world w){return std::make_pair(std::move(w), a);});
    }
     
    template<>
    template<typename T, typename U>
    auto Monad<IO>::bind(IO<T> ma, std::function<IO<U>(T)> f) -> IO<U>
    {
        // возвращаем IO с функцией, которая принимает "мир",
        // запускает на нем первое вычисление, получает "следующий мир" и новое значение,
        // затем вычисляем функцию от значения, получая новое IO вычисление,
        // которое и запускаем над "следующим миром"
        return IO<U>([=](real_world w) {
            auto world_and_data = ma.run(std::move(w));
            auto next_io = f(world_and_data.second);
            return next_io.run(std::move(world_and_data.first));
        });
    }


Теперь определим простейшие функции с IO, работающие через реальные функции с побочными эффектами
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    // заводим тип для "ничего", чтобы не заморачиваться с обработкой void
    struct unit {};
     
    auto putChar(char ch) -> IO<unit>
    {
        // Создаем IO с функцией, которая принимает "мир"
        // и выводит символ на экран, возвращая новый "мир"
        // (см. real_world::change)
        return IO<unit>([=](real_world w) {
            return w.change<unit>([=]{
                std::cout << ch;
                return unit{};
            });
        });
    };
     
    auto getChar(unit) -> IO<char>
    {
        // Создаем IO с функцией, которая принимает "мир"
        // и читает символ, возвращая новый "мир" и прочитанный символ
        // (см. real_world::change)
        return IO<char>([=](real_world w) {
            return w.change<char>([=]{
                char res;
                if (!std::cin.get(res).good()) return '\0'; // пока так
                return res;
            });
        });
    }


Теперь можно уже что-то сделать просто через IO и эти две функции.
Для начала реализуем вывод строк через putChar.
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    auto putLine(std::string str) -> IO<unit>
    {
        // если строка пустая, то возвращаем действие ввода-вывода,
        // которое выводит символ '\n',
        // и останавливаем рекурсию
        if (str.empty()) {
            return putChar('\n');
        }
        // возвращаем действие ввода-вывода, которое сначала выводит первый символ строки,
        // затем рекурсивно выводит остаток строки
        return putChar(str[0]) >> putLine(str.substr(1));
    }


Теперь функцию считывания строки:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    auto getLine(unit) -> IO<std::string>
    {
        // возвращаем действие ввода-вывода, которое считывает первый символ,
        // и если он означает конец строки,
        // то возвращает действие ввода-вывода, которое вернет пустую строку,
        // в противном же случае считываем(рекурсивно) строку и возвращаем действие ввода-вывода,
        // которое вернет сконкатенированную строку из принятого ранее символа и новой строки
        return getChar(unit{}) >>= [=](char ch) {
            if (ch == '\n' || ch == '\r' || ch == '\0') {
                return ret<IO>(std::string());
            }
            return getLine(unit{}) >>= [=](std::string str) {
                return ret<IO>(ch + str);
            };
        };
    }


Ну и проверяем.
Вот такой простой код в do-нотации:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    main = do
        putLine "What is your name?"
        name <- getLine
        putLine ("Nice to meet you, " ++ name ++ "!")

будет выглядеть вот так:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    int main()
    {
        // формируем вычисление ввода-вывода
        auto io_main =
            putLine("What is your name?") >>
            getLine(unit{})               >>= [=](std::string name) {
                return putLine("Nice to meet you, " + name + "!");
            };
     
        // запускаем вычисление
        io_main.run(real_world{});
    }


http://ideone.com/WYK5GA

Автор: D_KEY 23.12.15, 09:57
ХЗ зачем я все это делал, но было интересно :D

Автор: Oleg2004 23.12.15, 11:12
D_KEY
Да уж, продемонстрировали недюжинные познания. Жаль что во флейме, а так бы получили бы от меня +1 в тематике.
Придется это делать во флейме :D

Автор: shm 23.12.15, 11:28
Цитата D_KEY @
будет выглядеть вот так:

:crazy:

Автор: D_KEY 23.12.15, 12:10
Цитата shm @
Цитата D_KEY @
будет выглядеть вот так:

:crazy:

Ну do-нотация это просто сахар. На самом деле компилятор haskell сначала превратит
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    main = do
        putStrLn "What is your name?"
        name <- getLine
        putStrLn ("Nice to meet you, " ++ name ++ "!")

в
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    main =
        putStrLn "What is your name?" >>
        getLine                       >>= \name ->
            putStrLn ("Nice to meet you, " ++ name ++ "!")

а потом уже будет с этим работать. Тут разница с кодом
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    auto io_main =
        putLine("What is your name?") >>
        getLine(unit{})               >>= [=](auto name) {
            return putLine("Nice to meet you, " + name + "!");
        };

Не такая уж и большая, да? :)

do-нотацию для С++ придумать сложнее... Сишные "макросы" тут слабоваты, а шаблоны синтаксис объявлений не поменяют.

Добавлено
Но вообще это бесполезная для С++ штука. Монада для списков и то полезнее.

Автор: shm 23.12.15, 13:45
Цитата D_KEY @
Не такая уж и большая, да?

Не сильна большая, но мозг выносит сильнее.

Автор: Oleg2004 23.12.15, 14:12
Вот тут как раз в тему :)
А вот тут даже я кое что понял. :yes:
Но вот этого я не могу понять.
Да, ведь можно нагородить операторов типа например "<>+->-" совершенно бессмысленных с точки зрения общепринятого понимания их составляющих - и потом гордо объявить, что это - операция "приковывать цепью"(с) хрен знает что к хрен знает чему.
Понятно, что любой язык программирования есть чистейшей воды формальная система.
Но должны же быть и некие пределы. :(
С этой точки зрения всем знакомый нам знак интеграла есть пример очевидной формализации целого алгоритма!!! - но совершенно осмысленный и понятный.
Именно это обстоятельство меня и настораживает. Слишком субъективны термины, понятия, операции и прочие процессы.
А это описание вообще шедевр:
Цитата
В функциональном программировании монада - структура, которая представляет вычисления, определенные как последовательности шагов: тип со структурой монады определяет то, что это означает приковывать цепью операции или функции гнезда того типа вместе. Это позволяет программисту строить трубопроводы, которые обрабатывают данные в шагах, в которых каждое действие украшено дополнительными правилами обработки, предоставленными монадой.
:'(
После трубопровода надо вводить категории вентиля, заглушки, датчиков давления и прочая...потом перейдем к канализации - в смысле объединения трубопроводов как каналов потоков информации...задачи фильтрации потоков канализации и тд... :wacko:
PS
В потоковом программировании тоже есть интересные нововведения, как например "цвет данных"
Какой то философ сказал
"ни одна вещь не должна объясняться сложнее чем она есть на самом деле"

Автор: D_KEY 23.12.15, 14:23
О, там как раз для future реализация, то, что MyNameIsIgor говорил.

А вот do-нотацию я что-то не увидел...

Автор: korvin 23.12.15, 18:06
Цитата JoeUser @
Читал доку по Эрлангу, видел там вычисление функции как последовательность утверждений, де жа вю ... Пролог.

Э-м... Можешь слегка по-подробней? А то у меня возникает стойкое ощущение, что тебя слегка ввела в заблуждение Прологоподобная грамматика Эрланга.

Добавлено
Цитата D_KEY @
Но вообще это бесполезная для С++ штука. Монада для списков и то полезнее.

А вот чистому Си не повредили бы, чтобы проверки кодов ошибок синтаксически лучше выглядели б. В Rust, я так понимаю, это сделали через макрос try! ?

Добавлено
Цитата D_KEY @
do-нотацию для С++ придумать сложнее... Сишные "макросы" тут слабоваты, а шаблоны синтаксис объявлений не поменяют.

А оператор ; переопределить нельзя? Я вроде уже спрашивал этот вопрос, может, не у тебя, но на этом форуме.

Автор: D_KEY 23.12.15, 18:40
Цитата korvin @
А оператор ; переопределить нельзя? Я вроде уже спрашивал этот вопрос, может, не у тебя, но на этом форуме.

Нет, но operator , можно :)
Только я тут больше не о простой цепочке, а о <-. Т.е. даже если бы мы перегрузили ; , это бы не избавило нас от лямбд.

Автор: Oleg2004 23.12.15, 20:01
Цитата korvin @
А оператор ; переопределить нельзя? Я вроде уже спрашивал этот вопрос, может, не у тебя, но на этом форуме.

Оператора ";" увы не существует.
По крайней мере в существующих языках программирования.
https://en.wikipedia.org/wiki/Operator_%28c..._programming%29
Общепринятое определение оператора:
Цитата
an operator is an object that is capable of manipulating a value

Автор: D_KEY 23.12.15, 20:21
Цитата korvin @
Цитата D_KEY @
Но вообще это бесполезная для С++ штука. Монада для списков и то полезнее.

А вот чистому Си не повредили бы, чтобы проверки кодов ошибок синтаксически лучше выглядели б.

Ты имеешь в виду что-то вроде монады Either? Или ты вообще вне контекста обсуждения монад?

Добавлено
Цитата Oleg2004 @
Цитата korvin @
А оператор ; переопределить нельзя? Я вроде уже спрашивал этот вопрос, может, не у тебя, но на этом форуме.

Оператора ";" увы не существует.
По крайней мере в существующих языках программирования.
https://en.wikipedia.org/wiki/Operator_%28c..._programming%29
Общепринятое определение оператора:
Цитата
an operator is an object that is capable of manipulating a value

Ну вот монады позволяют как бы пеегружать ;
Не в C++ :)

Автор: Oleg2004 23.12.15, 20:31
Цитата D_KEY @
Ну вот монады позволяют как бы пеегружать ;

Скорее всего тогда он не соответствует определению оператора. :)
Могу согласиться, что разделитель(delimiter) может быть в любом языке определен как что угодно. Попробуйте перегрузить пробел " ". Это однопозиционный разделитель, который в современных языках не есть оператор ни в коем случае...
Не хватает семантики для существующих на клавиатуре одноклавишных символов - выдумываем двупозиционные, трех и т.д. В Javascript не шли путем перегрузки, а тупо вводили 3-х, 4-х и 5-ти позиционные.
Мне такой подход виден более очевидным.

Автор: DarkEld3r 24.12.15, 09:39
Цитата korvin @
В Rust, я так понимаю, это сделали через макрос try! ?
Можно и так сказать, но всё-таки этот макрос недостаточно гибкий и вообще выглядит костылём для
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    if (error) {
        return error;
    }

Чуть получше выглядят функции map/map_or/map_or_else/ для Option, но получается многословно. do-нотацию на макросах пытались делать, но выглядит тоже страшненько, кроме самых простых случаев:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    let l = mdo! {
            z =<< 1i32..11;
            x =<< 1..z;
            y =<< x..z;
            when x * x + y * y == z * z;
            ret ret((x, y, z))
        }.collect::<Vec<_>>();

Автор: D_KEY 24.12.15, 10:16
Цитата DarkEld3r @
но выглядит тоже страшненько

Да вроде не так и страшно. Особенно на фоне синтаксиса rust :D

Автор: korvin 24.12.15, 18:52
Цитата D_KEY @
Ты имеешь в виду что-то вроде монады Either?

Да, типа того. Конечно, есть ещё куча нюансов.

Добавлено
Цитата Oleg2004 @
Скорее всего тогда он не соответствует определению оператора. :)

Почему? Наоборот же, обычный оператор типа (Monad m => forall a b. m a -> (a -> m b) -> m b). Или я тебя не так понял?

Автор: D_KEY 24.12.15, 23:00
Цитата korvin @
Цитата D_KEY @
Ты имеешь в виду что-то вроде монады Either?

Да, типа того. Конечно, есть ещё куча нюансов.

Ну можно сделать для C++, примерно как я показал. Только синтаксически ты сам видел, какой отстой. А do-нотацию не сделать.

Автор: D_KEY 24.12.15, 23:08
Цитата Oleg2004 @
D_KEY
OffTop
Флеймовый рейтинг свой видели??? >:(

Ага :) Этот то ли смайк то ли ещё кто многим активным участникам политики "подарки" сделал
Довольно однообразные, кстати.

Автор: D_KEY 24.12.15, 23:13
Ну я на 100% не уверен, что это смайк.

Автор: Oleg2004 24.12.15, 23:16
Цитата korvin @
Наоборот же, обычный оператор типа (Monad m => forall a b. m a -> (a -> m b) -> m b). Или я тебя не так понял?

Операторов типа не существует как класса.
Так же как не существуют операторы DECLARE, IF, FOR, CASE и прочая. :yes:

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)