На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела:
1. Название темы - краткое описание кто/что против кого/чего
2. В первом сообщении - список параметров, по которым идет сравнение.
3. Старайтесь аргументировать свои высказывания. Фразы типа "Венда/Слюникс - ацтой" считаются флудом.
4. Давайте жить дружно и не доводить обсуждение до маразма и личных оскорблений.
Модераторы: Модераторы, Комодераторы
  
> Erlang vs Haskel
    Всем добрейшего времени суток!

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

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

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

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

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


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

      Не, ну может на какой-то особенной архитектуре так и будет, а в целом бред конечно.
        Почему сразу бред? Если просто в лоб решать какую-то задачу, то вполне может так случиться. Самым правильным тут будет поверить самому.
          Проверить, D_KEY?
            Скрытый текст
            Цитата shm @
            Не, ну может на какой-то особенной архитектуре так и будет, а в целом бред конечно.

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

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

            Ждем "функциональщиков" ... :)
              Цитата Qraizer @
              Проверить, D_KEY?

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

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

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

                  Я видел, как решение в лоб на C++ было быстрее кучи ручной работы на си. Тоже касается и C и ассемблера. Почему бы и тут этому не сработать?
                    Цитата D_KEY @
                    Если просто в лоб решать какую-то задачу, то вполне может так случиться.

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

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

                    Не, ну чисто теоретически можно придать экзотическую архитектуру, для которой функциональные языки будут "ближе".
                    Сообщение отредактировано: shm -
                      Лично меня смутило вот это:
                      Цитата
                      ...разница была объяснена написанием дополнительного С++-кода в рамках защитного программирования, управления памятью и кода для высокоуровневой коммуникации...
                      Легко привести примеры, когда эти факторы приводят к пессимизации кода.
                        Цитата shm @
                        функциональные языки будут "ближе"

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

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

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

                                Добавлено
                                А то на словах все такие уверенные... :D
                                  Цитата D_KEY @
                                  Давайте уже задачки решать, что попусту разговоры разговаривать?

                                  Функциональщиков бы заманить малеха ... :lol:
                                    Ну korvin, думаю, сможет что-нибудь продемонстрировать. Я попробую(ocaml, haskell), но не уверен, что мой код будет аутентичен.
                                      Цитата D_KEY @
                                      Я попробую(ocaml, haskell), но не уверен, что мой код будет аутентичен.

                                      Код предназначен для реализации некоего алгоритма - т.е. цепочки действий, исполнение которых в указанном порядке приведет к желаемому результату.
                                      Поэтому для любого кода первична постановка задачи - и описание предполагаемого решения ее с помощью этого кода.
                                      Так что начните с идеи - please :)
                                        Так давайте какую-нибудь задачку придумаем :-?
                                          В голову приходит только вычисление суммы ряда или поиск максимально-минимального в массиве... :) на худой конец транспонирование матрицы. :(
                                            Вообще в стартовом сообщение речь несколько о других задачах=) В литературе по Erlang'у попадаются примеры историй, когда переписывание на Erlang дало не только выигрыш в объеме кода и стоимости поддержки, но и в производительности. Благодаря erlang'овской модели многопоточности, в основном. И я не вижу в этом ничего необычного.
                                              Я с вами согласен. И в самом первом своем посте я как раз обратил внимание собеседников на вот это:
                                              Цитата
                                              что для изученных телекоммуникационных приложений код на Erlang был на 70-85 % короче, чем на С++, а производительность системы при переписывании кода с С++ на Erlang возросла почти на 100 %.

                                              и спросил - а ЧТО ЭТО???
                                              что такое - телекоммуникационное приложение? :wall: где Erlang превыше всех???
                                              Дальнейшее - молчание. (с) Гамлет <_<
                                                Цитата
                                                Erlang [ˈɜːlæŋ][2] — функциональный язык программирования со строгой динамической типизацией, предназначенный для создания распределённых вычислительных систем. Разработан и поддерживается компанией Ericsson. Язык включает в себя средства порождения параллельных легковесных процессов и их взаимодействия через обмен асинхронными сообщениями в соответствии с моделью акторов.

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

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

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


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

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

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

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

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

                                                  И тут вы правы.
                                                  В свое время лет 35 тому назад у меня был коллега, высококлассный программист, который знал только один язык - Фортран. Он мне как то сказал - я на этом языке могу написать программу для любой задачи. Любой.
                                                  Он был прав. По своему. Но Фортран - не предназначен для текстовой обработки. И такая программа была бы просто уродлива скорее всего.
                                                  Сообщение отредактировано: Oleg2004 -
                                                    Цитата D_KEY @
                                                    Так давайте какую-нибудь задачку придумаем
                                                    Какой-нибудь микросимулятор Ютуба подойдёт?
                                                      Цитата Qraizer @
                                                      Цитата D_KEY @
                                                      Так давайте какую-нибудь задачку придумаем
                                                      Какой-нибудь микросимулятор Ютуба подойдёт?

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

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

                                                          Добавлено
                                                          D_KEY, ну например, имея несколько, можно много, источников данных, например, файлов, по запросам отдавать их контент. Запросы могут приходить к разным источникам данных, а могут и к одному, контент запрашиваться из разных регионов источников, например, по разным смещениям от начала файлов, активных запросов может быть несколько в одно время, запросы на данные из некоего источника среднестатически запрашивают их последовательно расположенными порциями со среднестатически одинаковой периодичностью, но это не всегда так.
                                                          Короче, тут больше над кодом клиента надо работать для получения объективных оценок кода сервера.
                                                            Кто пояснит, что означает такая конструкция на Эрланге - а точнее что означают три точки - и как их набрать на клаве? :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 и так далее.

                                                            Спасибо ТС за тему, она была для меня полезной.
                                                            Так что для меня после ознакомления со всеми делами вопрос закрыт... :)
                                                            Сообщение отредактировано: Oleg2004 -
                                                              Цитата Oleg2004 @
                                                              ∴ x = 5

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



                                                              Что же касается темы. В Эрланге функциональщины почти столько же, сколько и в Си. Ну или в джава-скрипте. Как его сравнивать с Хаскеллом?
                                                                Цитата Oleg2004 @
                                                                как их набрать на клаве?
                                                                Alt+8756 на цифровой. :)
                                                                  Цитата 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)

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

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

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

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

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

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

                                                                      Так что, твой комент был не лишним, и сэкономил мне немножко времени. Пасип :rolleyes:
                                                                        Цитата korvin @
                                                                        Цитата Oleg2004 @ Вчера, 19:41
                                                                        ∴ x = 5
                                                                        А откуда ты это взял? Ни разу не встречался с таким символом. И гугл ничего не говорит.

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

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

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

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

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

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

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

                                                                              Ну а что? Не так уж сильно далеко от Си Эрланг ушёл в этом плане. Подумаешь, TCO есть... =)
                                                                                На шелловскую команду тоже не тянет :D
                                                                                Какой обалдуй будет писать такой символ, который на клаве не набрать одной клавишей :lool:
                                                                                И да, гугля молчит о нем как рыба об лед. :(
                                                                                  Цитата korvin @
                                                                                  Цитата MyNameIsIgor @
                                                                                  :wacko:

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

                                                                                  Не понимаю, почему недалеко. Все языки с вызовом по значению недалеко ушли?
                                                                                    Цитата Oleg2004 @
                                                                                    На шелловскую команду тоже не тянет :D

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

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

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

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

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

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

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

                                                                                      А куда он двигался? Что тебя смущает? Отсутствие монад?
                                                                                        Цитата korvin @
                                                                                        У тебя пиратский гугл.

                                                                                        Спасибо за наводку :yes:
                                                                                        +1.
                                                                                          Цитата MyNameIsIgor @
                                                                                          А куда он двигался? Что тебя смущает? Отсутствие монад?

                                                                                          В concurrency. А меня ничего не смущает. =) Ну, кроме того, что конкурентные процессы не чисты by-design.
                                                                                          Сообщение отредактировано: korvin -
                                                                                            Цитата korvin @
                                                                                            Цитата MyNameIsIgor @
                                                                                            А куда он двигался? Что тебя смущает? Отсутствие монад?

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

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

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

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

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

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

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

                                                                                                Есть какие-то объективные мерки?
                                                                                                  Цитата korvin @
                                                                                                  а в сторону функциональщины он сделал лишь пару небольших шагов от Си.

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

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

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

                                                                                                  korvin, ты как?

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

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

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

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

                                                                                                    Так код на Erlang сам по себе и есть do-нотация :yes: korvin подтвердит.
                                                                                                      Цитата MyNameIsIgor @
                                                                                                      Смысл монады не в интерфейсе, а в абстракции побочных эффектов.

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

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

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

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

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

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

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

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

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

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

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

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

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

                                                                                                            Интересно!

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

                                                                                                            Точно! Читал доку по Эрлангу, видел там вычисление функции как последовательность утверждений, де жа вю ... Пролог.
                                                                                                              Пока только просто монады, IO потом попробую изобразить.
                                                                                                              ExpandedWrap disabled
                                                                                                                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 нам не нужен, остальное можно как-то так изобразить:

                                                                                                              ExpandedWrap disabled
                                                                                                                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>;
                                                                                                                };

                                                                                                              Хелперы/операторы:
                                                                                                              ExpandedWrap disabled
                                                                                                                // 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.
                                                                                                              Проверяем на простой монаде:

                                                                                                              ExpandedWrap disabled
                                                                                                                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);
                                                                                                                }


                                                                                                              Проверяем на чем-нибудь простом:
                                                                                                              ExpandedWrap disabled
                                                                                                                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;
                                                                                                                }

                                                                                                              ExpandedWrap disabled
                                                                                                                12


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


                                                                                                              http://ideone.com/9AHtv1
                                                                                                              Сообщение отредактировано: D_KEY -
                                                                                                                Цитата D_KEY @
                                                                                                                fail нам не нужен, остальное можно как-то так изобразить:

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

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

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

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

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

                                                                                                                  Так и должно быть.
                                                                                                                    Цитата D_KEY @
                                                                                                                    Не, fail используется для других ситуаций.

                                                                                                                    А каких?
                                                                                                                      Цитата JoeUser @
                                                                                                                      Цитата D_KEY @
                                                                                                                      Не, fail используется для других ситуаций.

                                                                                                                      А каких?

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

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

                                                                                                                      Добавлено
                                                                                                                      Монаду IO реализую или вечером или завтра, сейчас надо работу работать :)
                                                                                                                        Цитата D_KEY @
                                                                                                                        Вместо (ret<value>(10) >>= succ) >>= succ хотелось бы писать ret<value>(10) >>= succ >>= succ, но тут у C++ другая ассоциативность >>= чем в haskell. Можно заменить >>= на какой-нибудь другой оператор, на &, например.
                                                                                                                        ExpandedWrap disabled
                                                                                                                          ret<value>(10) & succ & succ

                                                                                                                        Или на , :D

                                                                                                                        ExpandedWrap disabled
                                                                                                                          val x = (ret<value>(10), succ, succ, succ, succ);
                                                                                                                          Цитата D_KEY @
                                                                                                                          Он вызывается в случае ошибки сопоставления с образцом внутри монадического вычисления.

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

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


                                                                                                                            В монаде IO fail кидает ошибку. Проверяем:
                                                                                                                            ExpandedWrap disabled
                                                                                                                              main = testIO

                                                                                                                            ExpandedWrap disabled
                                                                                                                              main: user error (Pattern match failure in do expression...


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


                                                                                                                            Для списка fail просто возвращает пустой список. Проверяем:
                                                                                                                            ExpandedWrap disabled
                                                                                                                              main = print testList

                                                                                                                            ExpandedWrap disabled
                                                                                                                              []


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


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

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

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

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

                                                                                                                                  Ну да, в принципе, монада. Почти IO, только захардкоженная.
                                                                                                                                  Другое дело, что писать свои монады в таком же виде нельзя.
                                                                                                                                  Да и смысла считать это монадой особого нет. C++ изначально ничего не говорит о чистоте.
                                                                                                                                    Списки тоже монады.
                                                                                                                                    Потому можно написать:
                                                                                                                                    ExpandedWrap disabled
                                                                                                                                      fun = do
                                                                                                                                          x <- [1, 2, 3]
                                                                                                                                          y <- [4, 5, 6]
                                                                                                                                          return (x, y)
                                                                                                                                       
                                                                                                                                      main = print fun

                                                                                                                                    И получить:
                                                                                                                                    ExpandedWrap disabled
                                                                                                                                      [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]


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


                                                                                                                                    Т.е. так:
                                                                                                                                    ExpandedWrap disabled
                                                                                                                                      fun =
                                                                                                                                          [1, 2, 3] >>= (\x ->
                                                                                                                                              [4, 5, 6] >>= (\y ->
                                                                                                                                                  return (x, y)))


                                                                                                                                    Что на крестах выглядит примерно так:
                                                                                                                                    ExpandedWrap disabled
                                                                                                                                      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));
                                                                                                                                          };
                                                                                                                                      };


                                                                                                                                    С тем же результатом:
                                                                                                                                    ExpandedWrap disabled
                                                                                                                                      [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]


                                                                                                                                    Для этого нужно сделать списки и реализовать для них монаду.
                                                                                                                                    список(на основе вектора)
                                                                                                                                    ExpandedWrap disabled
                                                                                                                                      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);
                                                                                                                                      }


                                                                                                                                    Реализуем монаду для списка:
                                                                                                                                    ExpandedWrap disabled
                                                                                                                                      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;
                                                                                                                                      }


                                                                                                                                    Ну и для вывода пара вспомогательных функций:
                                                                                                                                    вывод пар и списков
                                                                                                                                    ExpandedWrap disabled
                                                                                                                                      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 -
                                                                                                                                      Теперь по поводу IO.

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

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

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

                                                                                                                                      Теперь возвращаемся к C++.
                                                                                                                                      ExpandedWrap disabled
                                                                                                                                        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:
                                                                                                                                      ExpandedWrap disabled
                                                                                                                                        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;
                                                                                                                                        };


                                                                                                                                      Реализуем монаду:
                                                                                                                                      ExpandedWrap disabled
                                                                                                                                        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, работающие через реальные функции с побочными эффектами
                                                                                                                                      ExpandedWrap disabled
                                                                                                                                        // заводим тип для "ничего", чтобы не заморачиваться с обработкой 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.
                                                                                                                                      ExpandedWrap disabled
                                                                                                                                        auto putLine(std::string str) -> IO<unit>
                                                                                                                                        {
                                                                                                                                            // если строка пустая, то возвращаем действие ввода-вывода,
                                                                                                                                            // которое выводит символ '\n',
                                                                                                                                            // и останавливаем рекурсию
                                                                                                                                            if (str.empty()) {
                                                                                                                                                return putChar('\n');
                                                                                                                                            }
                                                                                                                                            // возвращаем действие ввода-вывода, которое сначала выводит первый символ строки,
                                                                                                                                            // затем рекурсивно выводит остаток строки
                                                                                                                                            return putChar(str[0]) >> putLine(str.substr(1));
                                                                                                                                        }


                                                                                                                                      Теперь функцию считывания строки:
                                                                                                                                      ExpandedWrap disabled
                                                                                                                                        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-нотации:
                                                                                                                                      ExpandedWrap disabled
                                                                                                                                        main = do
                                                                                                                                            putLine "What is your name?"
                                                                                                                                            name <- getLine
                                                                                                                                            putLine ("Nice to meet you, " ++ name ++ "!")

                                                                                                                                      будет выглядеть вот так:
                                                                                                                                      ExpandedWrap disabled
                                                                                                                                        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 -
                                                                                                                                        ХЗ зачем я все это делал, но было интересно :D
                                                                                                                                          D_KEY
                                                                                                                                          Да уж, продемонстрировали недюжинные познания. Жаль что во флейме, а так бы получили бы от меня +1 в тематике.
                                                                                                                                          Придется это делать во флейме :D
                                                                                                                                            Цитата D_KEY @
                                                                                                                                            будет выглядеть вот так:

                                                                                                                                            :crazy:
                                                                                                                                              Цитата shm @
                                                                                                                                              Цитата D_KEY @
                                                                                                                                              будет выглядеть вот так:

                                                                                                                                              :crazy:

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

                                                                                                                                              в
                                                                                                                                              ExpandedWrap disabled
                                                                                                                                                main =
                                                                                                                                                    putStrLn "What is your name?" >>
                                                                                                                                                    getLine                       >>= \name ->
                                                                                                                                                        putStrLn ("Nice to meet you, " ++ name ++ "!")

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

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

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

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

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

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

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

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

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

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

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

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

                                                                                                                                                          Оператора ";" увы не существует.
                                                                                                                                                          По крайней мере в существующих языках программирования.
                                                                                                                                                          https://en.wikipedia.org/wiki/Operator_%28c..._programming%29
                                                                                                                                                          Общепринятое определение оператора:
                                                                                                                                                          Цитата
                                                                                                                                                          an operator is an object that is capable of manipulating a value
                                                                                                                                                            Цитата 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++ :)
                                                                                                                                                              Цитата D_KEY @
                                                                                                                                                              Ну вот монады позволяют как бы пеегружать ;

                                                                                                                                                              Скорее всего тогда он не соответствует определению оператора. :)
                                                                                                                                                              Могу согласиться, что разделитель(delimiter) может быть в любом языке определен как что угодно. Попробуйте перегрузить пробел " ". Это однопозиционный разделитель, который в современных языках не есть оператор ни в коем случае...
                                                                                                                                                              Не хватает семантики для существующих на клавиатуре одноклавишных символов - выдумываем двупозиционные, трех и т.д. В Javascript не шли путем перегрузки, а тупо вводили 3-х, 4-х и 5-ти позиционные.
                                                                                                                                                              Мне такой подход виден более очевидным.
                                                                                                                                                              Сообщение отредактировано: Oleg2004 -
                                                                                                                                                                Цитата korvin @
                                                                                                                                                                В Rust, я так понимаю, это сделали через макрос try! ?
                                                                                                                                                                Можно и так сказать, но всё-таки этот макрос недостаточно гибкий и вообще выглядит костылём для
                                                                                                                                                                ExpandedWrap disabled
                                                                                                                                                                  if (error) {
                                                                                                                                                                      return error;
                                                                                                                                                                  }

                                                                                                                                                                Чуть получше выглядят функции map/map_or/map_or_else/ для Option, но получается многословно. do-нотацию на макросах пытались делать, но выглядит тоже страшненько, кроме самых простых случаев:
                                                                                                                                                                ExpandedWrap disabled
                                                                                                                                                                  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<_>>();
                                                                                                                                                                Сообщение отредактировано: DarkEld3r -
                                                                                                                                                                  Цитата DarkEld3r @
                                                                                                                                                                  но выглядит тоже страшненько

                                                                                                                                                                  Да вроде не так и страшно. Особенно на фоне синтаксиса rust :D
                                                                                                                                                                    Цитата D_KEY @
                                                                                                                                                                    Ты имеешь в виду что-то вроде монады Either?

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

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

                                                                                                                                                                    Почему? Наоборот же, обычный оператор типа (Monad m => forall a b. m a -> (a -> m b) -> m b). Или я тебя не так понял?
                                                                                                                                                                      Цитата korvin @
                                                                                                                                                                      Цитата D_KEY @
                                                                                                                                                                      Ты имеешь в виду что-то вроде монады Either?

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

                                                                                                                                                                      Ну можно сделать для C++, примерно как я показал. Только синтаксически ты сам видел, какой отстой. А do-нотацию не сделать.
                                                                                                                                                                        Цитата Oleg2004 @
                                                                                                                                                                        D_KEY
                                                                                                                                                                        OffTop
                                                                                                                                                                        Флеймовый рейтинг свой видели??? >:(

                                                                                                                                                                        Ага :) Этот то ли смайк то ли ещё кто многим активным участникам политики "подарки" сделал
                                                                                                                                                                        Довольно однообразные, кстати.
                                                                                                                                                                          Ну я на 100% не уверен, что это смайк.
                                                                                                                                                                            Цитата korvin @
                                                                                                                                                                            Наоборот же, обычный оператор типа (Monad m => forall a b. m a -> (a -> m b) -> m b). Или я тебя не так понял?

                                                                                                                                                                            Операторов типа не существует как класса.
                                                                                                                                                                            Так же как не существуют операторы DECLARE, IF, FOR, CASE и прочая. :yes:
                                                                                                                                                                            Сообщение отредактировано: Oleg2004 -
                                                                                                                                                                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                                                                                                                            0 пользователей:


                                                                                                                                                                            Рейтинг@Mail.ru
                                                                                                                                                                            [ Script execution time: 0,2025 ]   [ 16 queries used ]   [ Generated: 28.03.24, 14:07 GMT ]