Однажды я разговаривал с основателем израильского стартапа, который разрабатывал скоростную базу данных на GPU. В их стеке были Haskell и C++, и основатель жаловался, как тяжело найти людей в команду. В Москву он прилетал в том числе искать хороших программистов.

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

Все, что я слышал про Хаскель со стороны с тех пор, сводилось к одному — «с ним шутки плохи». Чтобы узнать хаскелистов получше, я пришел с расспросами к ним в телеграм-чат. Было довольно страшно, и как оказалось, не зря.

О Хаскеле не стремятся говорить популярно, и на такие затеи, кажется, поглядывают с презрением. Уж если говорить — то с максимальной полнотой и объективностью. «Одно из характерных качеств Хаскеля как языка и сообщества в том, что они вместе не стремились стать популярными, дав простой ответ на популярные вопросы. Вместо этого выстраивали логичный principled путь решения реальных проблем, а не быстрого проникновения в сердце прохожего интересующегося» — написали мне там.

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

Денис Мирзоев (nolane): В университете по предмету «Языки программирования» мне предложили пройти курс на Coursera по Хаскелю за один дополнительный балл из ста. Потом ещё был курс функционального программирования, на котором проходили Хаскель. Написал курсовую и выпускную работу бакалавра по GHC. Нашёл работу в качестве Хаскель-программиста.

Было тяжело, и тяжело до сих пор. Когда начинаешь изучать Хаскель, приходится постигать очень много новых концепций. Это сложная работа. Буквально учишься программировать заново.

Многим сейчас будет трудно вспомнить, как они начинали свой путь в программировании, как трудно было понять, что такое «указатель», что такое «функция», что такое «класс». Возможно поэтому изучение Хаскеля даётся так тяжело. С возрастом становится труднее усваивать новое.

Doctor_Ryner: Однажды на испытательном сроке я завалился на Redux, поэтому, смотря уроки от его создателя, решил поближе с этим всем познакомится. Сначала применял изученные практики в JavaScript, но потом узнал о Haskell, который считается истинным функциональным языком. Меня сразу привлекла его элегантность и куча новых неизвестных мне концепций.

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

Юрий Сыровецкий (cblp): Сложнее всего изучать Хаскель вторым, когда не прошёл синдром утёнка к первому языку.

Чем хорош и чем плох язык?


Doctor_Ryner: Язык очень краткий, элегантный и гибкий, не зря на нем половина библиотек — это EDSL (как минимум такое впечатление).

Юрий Сыровецкий (cblp): Высокая выразительность, легко переносить предметную область в код, оптимальное сочетание императивной и функциональной парадигм. Легко строить абстракции над данными и алгоритмами, что позволяет думать о задаче, не отвлекаясь на несвязанные мелочи.

Джон Доу: Строгая сильная (я бы сказал, фашистская) типизация.

Игорь Шевнин (interphx): Очень выразительная система типов. Не настолько мощная, как у Idris или Agda, но достигает той золотой середины, когда выразить можно почти всё, и при этом вывод типов работает нормально. Не надо везде помечать их вручную.

Но мощная система типов заставляет внимательнее относиться к передаваемым значениям. Куча определений типов может выглядеть как бойлерплейт. Каждая команда использует свой набор расширений или не использует их вообще. Код более «плотный» — одна строчка часто несёт больше информации, чем в других языках, поэтому неопытному разработчику сложнее его читать.

Doctor_Ryner: Изучая Haskell, ты скорее всего наткнешься на высказывание «if it compiles, it is probably correct». Тут нет null, сама функциональная парадигма очень строга и принуждает тебя следовать определенным правилам, которые в большинстве случаев ведут к лучшему дизайну.

Например, в языке нет переменных — только константы. Тебе не приходится следить за тем, что и где ты присваиваешь. Haskell поощряет использование чистых функций, что ведет к отсутствию побочных эффектов. Функциональный дизайн просто заставляет программу работать как одно целое, в противовес ООП, где в мир выброшена куча объектов и объекты пытаются общаться друг с другом путем побочных эффектов, превращая приложение в непредсказуемое месиво. На работе достаточно страдаем от такого с C# в Unity.

Денис Мирзоев: Встроенная ленивость повышает выразительность языка. Многие алгоритмы становятся проще. Она может увеличить производительность, если результаты промежуточных вычислений не будут использоваться. (К примеру `head. sort` работает за линейное время).

Игорь Шевнин: Ленивая модель вычислений обычно помогает, но когда порядок вызова функций важен, может быть трудно разобраться, что происходит.

Doctor_Ryner: Он компилируемый, что сразу же дает огромный прирост в скорости.

Денис Мирзоев: По скорости сравним с Java, но не такой быстрый как C.

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

Doctor_Ryner: В стандартной библиотеке Prelude есть очень плохие функции наподобие read, head, readFile, которые могут выкинуть Exception и положить программу, вместо того, чтобы возвращать Maybe. Поэтому приходится использовать альтернативы или писать свои реализации.

Игорь Шевнин: Главная проблема — отсутствие стандартизации, вплоть до того, что многие заменяют стандартную библиотеку на одну из несовместимых между собой альтернатив. Есть разногласия в сообществе на тему того, какой должна быть стандартная библиотека, что должно входить в ядро языка, а что допиливаться расширениями, и по моим ощущениям это тормозит развитие языка.

Денис Мирзоев: Не хватает тулов: нет полноценной IDE, очень мало средств для замеров производительности, нет отладки «по шагам» — это вообще говоря фундаментальная проблема.

Для каких проектов Haskell подходит лучше всего?


Юрий Сыровецкий: Для сложных задач, связанных с безопасностью или деньгами, где высока цена ошибки.

Doctor_Ryner: Для всего, где нужно проводить вычисления, преобразование и анализ данных. Сильно удивлен, что Haskell менее популярен в Data Science, чем Python.

Игорь Шевнин: Я бы не рискнул использовать его для встраиваемых систем (производительность неплоха, но всё же есть значительный оверхэд по потреблению памяти из-за ленивых вычислений) и мелких скриптов (там эта строгость просто не нужна). Также надо понимать, что найти разработчиков в команду намного сложнее, чем для мейнстримных языков.

Джон Доу: Чтобы писать промышленный код, который будут читать другие — вам нужна будет целая команда хаскеллистов. Такую мало кому удалось собрать.

Игорь Шевнин: Но благодаря краткости и строгости Haskell подходит почти для любых задач.

Начинать изучать разработку с Haskell — хорошая идея?


Игорь Шевнин: Начинать — вряд ли, потому что подавляющее большинство кодовых баз, с которыми человеку придётся работать, написаны не на нём.

Джон Доу: Плохая, плохая идея! Языки не из семейства ML — а такие из промышленных вообще все — потом будут для вас шоком.

Денис Мирзоев: Обычно люди сначала изучают математику, потом переходят к программированию. Поэтому изучение языка, использующего математические концепции (алгебраические типы данных, чистые функции), должно быть проще императивных. То есть я считаю, что это хорошая идея.

Doctor_Ryner: Всех новичков, которых я обучаю, я обязательно знакомлю с Haskell. Люди, которые не изучали императивные стиль, гораздо проще ориентируются в функциональном коде и быстрее учатся, потом даже если работают с объектно-ориентированными языками, они привносят хорошие архитектурные решения и функциональные практики.

Юрий Сыровецкий: Начинать лучше сразу с нескольких принципиально разных языков, например, Си, Хаскель и Смолток, в любом порядке. Ни один язык в
отдельности не даст полного понимания.

Haskell — достаточно старый язык. Это хорошо или плохо?


Юрий Сыровецкий: Развивается язык очень активно, груз совместимости только ради совместимости не тянет.

Джон Доу: Стандарт принят в 1998-ом, но это не заметно: до сих пор новые версии компилятора, потенциально ломающие обратную совместимость, выходят примерно раз в полгода.

Денис Мирзоев: Haskell не старый, а проверенный временем. В язык никогда не попадут непродуманные изменения. Так что это скорее хорошо.

Про Haskell говорят, что это один самых сложных языков. Это так?


Doctor_Ryner: Как сам язык — нет. Сложны скорее абстракции, которые в нем используются. Человек, который никогда не видел кода на Haskell, может просто сойти с ума от потока новой информации и разных непривычных конструкций.

Масло в огонь подливает то, что язык накладывает кучу «ограничений», не позволяет или сильно затрудняет кучу вещей, которые не вписываются в функциональную концепцию.

Джон Доу: Чтобы первый элементарный проект хотя бы просто скомпилировался, ушло почти два месяца курения учебников, мануалов и туториалов по вечерам. Правда скомпилировавшись, проект сразу заработал и фигачил под полной нагрузкой (6k rps с пиками до 15) полгода, без изменений вообще.

Денис Мирзоев: Готов поспорить, что если школьник начнёт изучать программирование с Хаскеля и продвинется достаточно далеко, то императивное программирование ему покажется более сложным и менее интуитивным.

Игорь Шевнин: Сложность относительна. Из мейнстримных языков я всё ещё считаю C++ самым сложным. Языки для доказательства теорем (Agda, Coq) будут посложнее Хаскелля в концептуальном смысле. Haskell — несложный язык, но его паттерны и библиотеки — стандартные и сторонние — выучить удастся далеко не сразу.

Всегда ли его сложность оправдана?


Игорь Шевнин: Паттерны и высокий уровень абстракции оправданы, так как делают код надёжнее и короче. Но думаю, что операторы, имена функций и многие другие вещи могли бы быть понятнее.

Doctor_Ryner: Зачастую сложные конструкции Haskell позволяют создавать очень короткие решения, которые еще и оказываются очень гибкими и модульными.

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

Джон Доу: Язык для привыкших к обычным python/php/whatever вообще производит впечатление ортогонального к реальности. Для людей, которые изначально не интересовались теорией категорий, добиться результатов с абсолютного нуля — очень тяжело.

Но когда понимаешь язык — получаешь новый способ думать о решаемой проблеме.

Haskell видится языком как будто для математиков, а не для разработчиков. Как думаете, он не распространен широко из-за этого?


Денис Мирзоев: Это демонстрация принципа, которому следуют главные разработчики Хаскеля — «avoid success at all costs». Смысл, конечно, не в том, что нужно избегать успеха, а в том, что нужно избегать успеха, цена которого слишком высока.

Можно было сделать Хаскель популярным. Есть, к примеру, поддержка этого языка со стороны Microsoft. Можно было сделать язык более императивным, принимать какие-то быстрые и непродуманные решения, чтобы завоевать популярность. Можно было использовать много грязных приёмов, но благодаря такой правильной позиции главных разработчиков ничего подобного не было.

Да, популярность языка не очень высока, но зато не страдает его качество. Мне очевидны преимущества Хаскеля по отношению к императивным языкам, большинство его проблем разрешимы, поэтому я уверен, что большая популярность ещё придёт по мере его развития.

Юрий Сыровецкий: Таким он видится только людям, ничего про него не знающим. В
«реальной» разработке Хаскель применяется давно, примеры легко найти в
вашей любимой поисковой системе. В частности, мы в ЛК использованием
Хаскеля довольны, и ничего другого на его месте не видим.

Игорь Шевнин: Что такое «язык для математиков» я толком не знаю. Это либо R/MatLab/Mathematica для расчётов и статистики, либо Python, потому что он простой и требует меньше инженерного бэкграунда. Но не Haskell. Алгебраические понятия типа моноидов используются в нём из практических соображений, а не только для дополнительной строгости.

Основную роль в популярности сыграла историческая распространённость C/C++/Java/C# в энтерпрайзе, они заняли нишу. Но сейчас многие компании начинают использовать Haskell и другие функциональные языки.

С каким япом ты бы сравнил Haskell и в чью пользу?


Джон Доу: Из более или менее распространенных — с Erlang. Но на Erlang все же проще писать и его проще выучить, как мне кажется.

Денис Мирзоев: Я хорошо знаю C, С++, Java и Haskell. C++ даже сравнивать ни с чем не надо, язык ужасен. Си — хороший язык для низкоуровневой разработки. В этой нише он будет лучше. В остальном я бы предпочёл Haskell.

Выбор между Java и Haskell уже труднее, но тут тоже нужно смотреть на конкретную задачу. Под андроид на Haskell будет скорее всего трудно писать, в этом случае лучше Java. А вот сервера писать на Haskell почти также удобно как и на Java. Если окружение позволяет — тулинг, доступность библиотек, — то я обычно выбираю Haskell.

Doctor_Ryner: С C#, достаточно погуглить, как реализовать Maybe на C# и на Haskell. Очень странно, что диктаторский чисто функциональный Haskell чувствуется гораздо более гибким и свободным. На самом деле это две крайности.

С# один из самых объектно-ориентированных языков, и преимущества Haskell сильно контрастируют с ним. В С# тебе постоянно приходится писать кучу лишних вещей, и это все очень неприятно. Использование функций высшего порядка может уродовать код в плане синтаксиса. На фоне всего этого уже сложно вернуться с коротких и элегантных решений Haskell

Игорь Шевнин: С Rust, пока что в пользу Rust. Он берёт очень многое от Haskell и других ФП-языков, но при этом дружит функциональный подход с императивным, а разработчики и сообщество намного грамотнее и более последовательно подошли к развитию языка с самого начала.

Что думаете про сообщество хаскелистов?


Джон Доу: Подавляющее большинство — очень дружелюбные люди, всегда готовые помочь. Приятное отличие от сообществ многих других языков.

Doctor_Ryner: Haskell сообщества зачастую содержат в себе пугающе умных людей, которые всегда готовы помочь. Не зря ходят локальные мемы про PhD, теорию категорий и академиков. Если заходя в чат по другим языкам, ты видишь, что люди обсуждают обычные production-проблемы и структуры данных. В чате по Haskell перед тобой сразу выскакивают монады, лемма Йонеды, аппликативные функторы, написание безумных типов и прочее-прочее.

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

Говорят, хаскелисты высокомерные. Правда?


Денис Мирзоев: Да. Мне кажется высокомерность связана с тем, что они очень любят свой язык и расстроены его недооценённостью.

Джон Доу: Нифига подобного.

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

Игорь Шевнин: Высокомерие — слишком сильное слово. Тут скорее дело в том, что ФП, ООП, различие ООП-классов и union types, extension problem и много других понятий однажды складываются в очень чёткую картинку, и после этого становится трудно воспринимать людей, которые пытаются противопоставить ООП и ФП или другим образом представить широкую проблему в узкой перспективе.

Почему ФП-языки до сих пор нишевые?


Денис Мирзоев: Их преимуществ всё ещё не достаточно, чтобы заинтересовать большое количество программистов. Трудность в изучении не способствует популярности. Проблемы с тулингом тоже многих отпугивают, а мне кажется как раз увеличение численности сообщества могло бы решить эту проблему. Получается замкнутый круг.

Игорь Шевнин: Нишевость постепенно проходит, а функциональные концепции подтягиваются в другие языки.

Doctor_Ryner: Сами функциональные принципы и языки, что их поддерживают, уже повсеместны. Даже для шарпов есть Linq и некоторые другие библиотеки. Нишевые скорее чисто функциональные языки, так как в них используются нестандартные концепции.

Не стоит забывать, что еще лет 20 назад железо было не достаточно производительным для функциональных языков, так что в мейнстрим функциональщина начала входить в последние годы, а интерес к Haskell только растет.

Комментарии (102)


  1. capslocky
    05.02.2019 16:14
    +4

    Жаль, что Haskell не был моим первым языком программирования. Очень интересно, какими разработчиками станут те школьники (студенты), которые начнут с Haskell и далее еще что-то функциональное, вроде Scala или F#.


    1. Alter2
      05.02.2019 23:24
      +1

      Ещё интересней будет посмотреть на результаты, если Haskell будет первым языком программирования для ребенка, родной язык которого — ифкуиль.


      1. KvanTTT
        05.02.2019 23:39

        Не выдержит несовершенство этого мира.


      1. artemisia_borealis
        06.02.2019 00:48

        Тогда уже лучше Ложбан пусть будет первым родным. Он всё-таки функциональный в каком-то смысле, и более простой, и носители есть. В случае с Ыфкуилем полный швах, нет у меня уверенности, что его кто-то знает.


  1. BiosUefi
    05.02.2019 17:40
    +4

    >>лет 20 назад железо было не достаточно производительным для функциональных языков

    ой, дайте мне это развидеть.


    1. rumkin
      05.02.2019 18:39
      -1

      Вполне справедливое высказывание. Оверхед от иммутабильности мог сойти за аргумент в пользу языков с ручным управлением памятью.


      1. Szer
        05.02.2019 22:17
        +2

        Ну да, ну да.


        А LISP как интересно существовал? На нём писались и пишутся (на диалектах) очень сложные программы.


        1. vassabi
          05.02.2019 22:20
          +3

          а для него делали специальное железо

          ....


        1. cblp
          05.02.2019 22:35
          +2

          Лисп — обычный императивный язык, там мало функциональщины и иммутабельности.


          1. idea-list
            06.02.2019 01:09

            Искренний вопрос: можете более детально объяснить, почему так?
            Мне непонятно, потому что ещё в универе мне преподавали на нем ФП + я сходу не вижу почему он на считается функциональным.


            1. vsb
              06.02.2019 02:43

              Лисп ненамного функциональней, чем JavaScript, например. В универах обычно преподают C, Pascal, примитивный С++ сначала, на них функциональное программирование выглядит громоздко и неуместно. По сравнению с ними лисп действительно вполне функционален. Если преподавать Python, JavaScript, тут уже каких-то преимуществ у лиспа не будет. Разве что списки лисповые и задачи на них позволяют хорошо въехать в иммутабельные списки, но в общем-то каркать и кдрать можно хоть на чём.


              1. idea-list
                06.02.2019 04:16

                JS стал перенимать функциональные штуки не так давно. Python, по моему опыту не слишком удобен в ФП. Да, в этих языках есть средства для ФП, как и во многих других, но я не понимаю как это делает Лисп не функциональным языком?


                1. cblp
                  06.02.2019 08:28

                  Конечно, он функциональный! Для некоторого определения «функционального».


                1. vsb
                  07.02.2019 00:03
                  +1

                  Соглашусь, что тут вопрос в определениях. Меня учили, что функциональный стиль программирования это когда функции передаются в качестве параметра. Передавать функции параметром в C формально можно, но писанины много и замыканий нет, замыкания придется делать самому через дополнительный контекстный параметр. Да и объявить функцию тут же аргументом нельзя, надо объявлять отдельно. В паскале то же самое. В том же лиспе это выглядит весьма естественно и в JS это всё было с самого начала. Не зря ходят байки, что JS это лисп с сишным синтаксисом. Если для вас ФП это иммутабельные структуры и вообще иммутабельность во все края, то да, JS тут не слишком хорош, хотя с современным синтаксисом можно что-то изобразить, но тут и традиционные лиспы не подойдут, там везде есть мутабельность.


                  1. cblp
                    07.02.2019 00:10

                    1. Druu
                      07.02.2019 06:50

                      Схема ж не лисп.


                  1. cblp
                    07.02.2019 00:12

                    Передавать функции в качестве параметра — downwards funarg problem — это лишь малая часть функционального стиля.


                1. potan
                  07.02.2019 13:30

                  Лисп — не один язык, а больщое симейство.
                  В Common Lisp стандартная библиотека рассчитана на мутабельность всего и вся, не требуется и часто не делается оптимизация хвостовых вызовов, очень сильно развиты конструкции циклов, для функций высщих порядков требуется специальные конструкции.
                  Scheme вполне функциональный. Мутабельность там изредка используется для оптимизации, но без нее удобно обходиться.


                  1. newpy
                    08.02.2019 17:32

                    Странно что никто Clojure не вспомнил/упомянул в качестве современного диалекта Лиспа, где иммутабельность из коробки, впрочем элемент «мутабельности» там тоже присутствует там где это необходимо. И Clojure вполне себе функциональный язык.


            1. cblp
              06.02.2019 08:26

              Я не глубокий специалист в лиспе, надеюсь, кто-нибудь поправит. Знаю только, что есть много разных лиспов: изначальный Лисп МакКарти — совсем императивный, в Common Lisp есть элементы ФП, в Scheme их ещё больше.

              Преподавали, наверно, потому что в нём есть базовые элементы ФП — лямбда-абстракция и замыкание, а также односвязный список в сердце языка. Но шаг в сторону — и появляются мутации. С комбинаторами не так удобно работать, как в языках с синтаксисом ISWYM (*ML, Haskell). С таким же успехом можно на Питоне и С++ преподавать ФП.

              Так что Лиспы считаются функциональными, но примерно в той же степени, что и Питон.


        1. tbl
          06.02.2019 00:39

          Попробуй без Data.Map реализовать tree на обычных языковых конструкциях haskell типа списков и кортежей хотя бы бинарное красно-черное дерево с ребалансировкой и прочими удовольствиями. Я после прочтения туториала долго плевался от скорости языка, когда в качестве самостоятельного задания делал компрессию с использованием huffman tree. Только гораздо позже плотно познакомился с IO()-монадой и понял ее мощь для работы внутри языка, а не только как средство для общения с внешним миром.

          Я к тому, что структуры, внешне выглядящими иммутабельными, для внутренних алгоритмов необязательно должны быть иммутабельными.


          1. 0xd34df00d
            06.02.2019 00:55

            Я к тому, что структуры, внешне выглядящими иммутабельными, для внутренних алгоритмов необязательно должны быть иммутабельными.

            Тогда лучше ST, а не IO.


            А вообще, говорят, книжка Окасаки, Purely functional data structures, весьма хороша. Но я её ещё, увы, не читал.


            1. tbl
              06.02.2019 01:01

              Спасибо, посмотрю


            1. a_e_tsvetkov
              07.02.2019 11:02
              +1

              Книжка чудо как хороша. И красно-черные деревья там кажется есть.


    1. Doctor_Ryner
      05.02.2019 19:02
      +1

      Стоит понимать что «недостаточно» не значит «невозможно», но излишняя нагрузка на память, иммутабельность и кол-во занимаемого дискового пространство вовсе не шли на пользу развития языка и стоит понимать что я имел ввиду именно чистые функциональные языки на производительность которых жалуются до сих пор, не говоря уже о конце 90-ых


    1. 0xd34df00d
      05.02.2019 20:31
      +5

      Действительно, ведь за 20 лет мы скорее научились существенно более эффективно компилировать функциональный код. ghc прям алмаз с точки зрения технологии компиляторостроения.

      А иммутабельность вообще упрощает сборку мусора, например.


      1. Druu
        05.02.2019 20:59
        +3

        Не надо еще забывать, что затраты на сборку мусора обратно пропорциональны количеству памяти в системе.
        Сейчас с дешевой памятью все на порядок лучше, чем 20 лет назад, и сборщики могут позволить себе работать быстро.


  1. potan
    05.02.2019 18:30
    +7

    Могу рассказать о себе.
    Когда я заинтересовался функциональным программированием (где-то в районе 2000 года, я тогда программировал на C код для ядра FreeBSD), я решил изучить сразу два языка, написав интерпретатор Рефал-подобного языка на Haskell. Ввод/вывод я не поддерживал, что сильно упростило задачу — через пару дней интерпретатор работал. Что меня поразило — ошибка, которую не отловил компилятор, была всего одна, в грамматике, которая генерировалась happy. Очень помогла ленивость — компилятор создавал список функций, а когда требовалась сосластья на другую функцию, я просто искал ее в этом списке, хотя она могла компилироваться позже. С монадами я тогда не разобрался — чтение программы с консоли и вывод результатов компилировал методом научного тыка.
    Потом я принял небольшое участие в одном исследовательском проекте (найденом через рефаловское комьюнити). Неожиданностью было что добавление pretty print результатов в пару десятков строк увеличивало время работы с 4 до 6 минут.
    Увлекаясь защитой информации, я дал простунькую программу на Haskell очень крутому реверсеру для дизассемблирования — минут через 15 он ответил Nightmare.
    Потом на каком-то форуме ввязался в обсуждения моделирования rs-триггера — решение на Haskell за счет ленивости оказалось тривиальным. Оно отличалось от предлагаемых на форуме «горизонтальным временем» — я выводил состояния сигралов в каждой точке в отдельной строке. Переписывания вывода в столбик увеличило программу раза в 2.5 (хотя на больших интервалах моделирования она бы работала быстрее). Правда, потом там решили, что «горизонтальное время» больше похоже на работу с осцилографом.
    Очень помогло в изучении чтение статьи The Evolution of a Haskell Programmer.
    Когда меня занесло в контору, разрабатывающую микросхемы, оказалось что Haskell — идеальный язык для моделирования подобных систем. Правда, из-за ленивости, на больши интервалах начиналась утечка памяти, с которой было тяжело бороться (хотя для моделей проблема не критичная).
    Далее знание Haskell мне очень помогло в освоении Scala (при этом почти не зная Java или C#). А это сейчас один из самых высокооблачиваемых языков, Scala-сеньеров на рынке расхватывают как горячие пирожки. Уже ради этого Haskell имеет смысл учить как первый язык.


    1. 0xd34df00d
      05.02.2019 20:36
      +2

      Правда, из-за ленивости, на больши интервалах начиналась утечка памяти, с которой было тяжело бороться (хотя для моделей проблема не критичная).

      А, кстати, чего там? Если соответствующий путь в алгоритме можно воспроизвести на достаточно маленьких данных, то сборка со всякими -prof -fprof-* (ну или stack build --profile, мы ж в 2019), и потом +RTS -h или -hr (hr вот вообще крутота для такого, меня выручал).


      1. potan
        05.02.2019 22:07

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


  1. potan
    05.02.2019 18:49
    +4

    Еще о практичности Haskell — в Лаборатории Касперского его используют для кодогенерации в встраевоемой ОС (с помощью библиотеки Ivory). То есть он даже в embedded полезен, особенно с учетем стоимости ошибок.


  1. Throwable
    05.02.2019 19:53
    -1

    Игорь Шевнин: Ленивая модель вычислений обычно помогает, но когда порядок вызова функций важен, может быть трудно разобраться, что происходит.

    Когда порядок функций важен (например когда надо приготовить файл или написать в базу), вы должны въявную это указывать при помощи IO/do, что как бы и есть императивное программирование. Другое дело, что ваш Хаскель таки на ура разрешает сайд-эффекты, а далеко не каждый разработчик сможет их увидеть. И в один прекрасный момент вместо (INSERT-UPDATE) выполняется (UPDATE-INSERT), вызывая очередную головную боль.


    Игорь Шевнин: Но благодаря краткости и строгости Haskell подходит почти для любых задач.
    Doctor_Ryner: Зачастую сложные конструкции Haskell позволяют создавать очень короткие решения, которые еще и оказываются очень гибкими и модульными.

    Короткие не значит понятные. Был такой write-only язык Perl, там тоже были короткие однострочники, в которых сам автор уже через неделю нифига не шарил.


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

    В ООП мире моделируется система сущностей, наиболее приближенная к реальному миру, а также ее эволюция во времени. В ФП моделируются абстрактные преобразования над исходными данными. Но тем не менее на определенном этапе любое ФП всегда скатывается в императивное программирование, например, когда нужно осуществить системные вызовы в определенной последовательности, и именно здесь начинаются настоящие сайд-эффекты. Без этого никак.


    Но мощная система типов заставляет внимательнее относиться к передаваемым значениям. Куча определений типов может выглядеть как бойлерплейт.

    В том-то и дело. С одной стороны, мы хотим дать исчерпывающее описание предметной области на этапе декларации, чтобы компилятор отловил как можно больше и т.д. С другой стороны, а так ли это необходимо, и стоит ли платить за это ценой простоты и понятности кода, когда проще поставить в коде пару assert-ов или ручных приведений типов? Если учесть, что большинство сегодня вообще пишет без типов (JS, Python) и как-то худо-бедно справляется. Когда вы объясните клиенту, как моноиды и полугруппы связаны с его прибылью, тогда и поговорим за мощную систему типов.


    Под андроид на Haskell будет скорее всего трудно писать, в этом случае лучше Java. А вот сервера писать на Haskell почти также удобно как и на Java.

    Уже смущает слово "почти". Как только прикрутите к серверу базу данных, так у вас появится мутабельный стейт, и вся девственная чистота функций будет варварски сломана. Поэтому код потребует императивного последовательного применения изменений стейта, что не сильно будет отличаться от кода на Java + фреймворк.


    Масло в огонь подливает то, что язык накладывает кучу «ограничений», не позволяет или сильно затрудняет кучу вещей, которые не вписываются в функциональную концепцию.

    Ну да, это как всегда задачи виноваты, что не подходят под такой прекрасный язык.


    Джон Доу: Чтобы первый элементарный проект хотя бы просто скомпилировался, ушло почти два месяца курения учебников, мануалов и туториалов по вечерам.

    Прям мытарства какие-то с религиозным оттенком. На Ноде, РубиРейлсе или Спрингбуте через 5 минут уже все запустится, и работать будет не хуже. С таким же успехом можно программировать на брейнфаке и гордиться этим. Концептуальненько! Любой же нуб хочет сразу видеть что-то работающее, а уже потом разбираться с этим. На два месяца терпения ни у никого не хватит.


    Денис Мирзоев: Да. Мне кажется высокомерность связана с тем, что они очень любят свой язык и расстроены его недооценённостью.

    Высокомерность говорит о том, что в большинстве случаев ЧСВ — это единственная мотивация почему эти люди изучили Хаскель. Компенсируют что-то.


    Вобщем, набор противоречащих мнений и отзывов. Поэтому стоит делать из Хаскеля очередного карго-культа, а из хаскелистов богов-гуру. В конце-концов, каждый мочит как он хочет.


    1. cblp
      05.02.2019 19:58
      +2

      Хаскель не меняет местами эффекты, так что


      И в один прекрасный момент вместо (INSERT-UPDATE) выполняется (UPDATE-INSERT), вызывая очередную головную боль.

      это невозможно.


    1. cblp
      05.02.2019 20:00
      +2

      Короткие не значит понятные.

      Да, но с коротким текстом проще добиться понятности, чем с длинным.


      1. Druu
        05.02.2019 21:05
        -1

        Да, но с коротким текстом проще добиться понятности, чем с длинным.

        Это не так. Можете взять какой-нибудь текст и удалить пробелы, знаки препинания, окончания слов — понятнее не станет.


        1. cblp
          05.02.2019 21:20
          +1

          Если добавить пробелы или буквы, тоже понятнее не станет. И что?

          Нет, это в обратную сторону работает. Если текст понятный, то он будет скорее короткий, чем длинный (при равном количестве информации).


          1. tbl
            06.02.2019 01:09

            Ну вот, например, оператор «сиськи»:

            (.).(.)

            Без :t мне было сложно определить, что это тоже самое, что и инфиксный оператор «точка»:
            .
            , но только для функций с двумя аргументами. По мне так, когда в коде встретишь, сразу и не поймешь значение иероглифа, если ранее не встречал такую конструкцию.


          1. Druu
            06.02.2019 08:49

            Если добавить пробелы или буквы, тоже понятнее не станет.

            Ну и что?


            Если текст понятный, то он будет скорее короткий, чем длинный (при равном количестве информации).

            Выше я привел контрпример, который показывает, что это не так.


            (при равном количестве информации)

            Практически невозможно написать более короткий код с тем же количеством информации, если начальный код не был намеренно раздут. В том и дело. То есть фактически вы написали:


            Если текст понятный, то он будет скорее короткий, чем длинный (но только в том случае, который недостижим на практике).


            1. cblp
              06.02.2019 10:33

            1. cblp
              06.02.2019 10:34

              Текст почти всегда раздувается ненамеренно.


              1. Druu
                06.02.2019 16:45

                Текст почти всегда раздувается ненамеренно.

                Тогда и короче без потери в читабельности написать не выйдет.


                glvrd.ru

                Очень плохо работает. Вставил две строчки из предыдущего поста — и все 4 указания из 4 были ошибочными.


      1. tbl
        06.02.2019 00:55

        иногда с point-free нотацией можно такую скороговорку написать, что без «100 грамм» не разберешь, особенно в этом плане выдаются APL-подобные языки вроде J.


        1. potan
          06.02.2019 12:30
          +1

          Да, но в языках со статической типизацией типы подвыражений очень хорошо помогают в таком коде разбираться.


    1. cblp
      05.02.2019 20:02

      и именно здесь начинаются настоящие сайд-эффекты. Без этого никак.

      Правильно, поэтому полезнее оказывается язык, в котором сайд-эффектами можно управлять.


      1. potan
        06.02.2019 12:30
        +1

        Собственно для этого монады и придуманы.


        1. cblp
          06.02.2019 12:50

          И не только монады.


    1. cblp
      05.02.2019 20:05
      -2

      Когда вы объясните клиенту, как моноиды и полугруппы связаны с его прибылью, тогда и поговорим за мощную систему типов.

      Своему клиенту мы объяснили. Вы хотите, чтобы мы объяснили вашему клиенту? Вы сами не в состоянии?


    1. cblp
      05.02.2019 20:05

      Как только прикрутите к серверу базу данных, так у вас появится мутабельный стейт, и вся девственная чистота функций будет варварски сломана.

      Сами себе противоречите.


    1. cblp
      05.02.2019 20:11

      через 5 минут уже все запустится

      На Хаскеле меньше 5 минут. Или вы экстраполировали ошибку одного человека на всю технологию?


    1. JC_IIB
      05.02.2019 20:29
      +4

      В ООП мире моделируется система сущностей, наиболее приближенная к реальному миру

      Это может быть и заблуждение. Как я уже писал, у кого-то из мэтров программирования я встречал мнение, что на самом деле ООП исключительно плохо натягивается на реальный мир. А, ну и чтоб два раза не вставать — «С наследованием оно не натягивается вообще никак (потому что ко/контравариантность) без адовых костылей.» (С) 0xd34df00d
      На Ноде,

      Пишите на Ноде, в чем проблема-то? Вас страшные Хаскелисты тащат крючьями к себе, тряся монадами?
      В конце-концов, каждый мочит как он хочет.

      Вот эта фраза лишает смысла весь ваш комментарий.


    1. 0xd34df00d
      05.02.2019 20:43
      +4

      Другое дело, что ваш Хаскель таки на ура разрешает сайд-эффекты, а далеко не каждый разработчик сможет их увидеть. И в один прекрасный момент вместо (INSERT-UPDATE) выполняется (UPDATE-INSERT), вызывая очередную головную боль.

      В IO? Ну да, ещё бы не разрешал.


      Хотите гарантировать порядок INSERT/UPDATE уже внутри do — вам в идрис (ну или в свободные монады + GADT + синглтоны). Что, кстати, довольно иронично перекликается с вашим тезисом о нужности типов позже.


      Короткие не значит понятные.

      Это в основном к типам относится. Ну да, есть даже такое высказывание:
      «Java's architecture astronauts are well known. Dependently typed languages enable something much worse: type astronauts. A function cannot merely be written that works on some concrete type. It needs to be abstracted and abstracted until it operates on elements of some obscure algebraic structure mentioned once, in passing, in a PhD thesis in 1983.»


      Но тем не менее на определенном этапе любое ФП всегда скатывается в императивное программирование, например, когда нужно осуществить системные вызовы в определенной последовательности, и именно здесь начинаются настоящие сайд-эффекты.

      Выделять какую-то функциональщину (или декларативщину) как основной признак хаскеля — непонимание сути™. Основной смысл в разделении эффектов и возможность выразить пусть и императивную предметную область максимально типобезопасно.


      Когда вы объясните клиенту, как моноиды и полугруппы связаны с его прибылью, тогда и поговорим за мощную систему типов.

      Я просто делаю за три месяца то, что соседняя команда обещала сделать за 9, и у меня всё готово, работает и устойчиво к изменяющимся требованиям (потому что ничего не отваливается в рантайме из-за изменений).


      Как только прикрутите к серверу базу данных, так у вас появится мутабельный стейт, и вся девственная чистота функций будет варварски сломана. Поэтому код потребует императивного последовательного применения изменений стейта, что не сильно будет отличаться от кода на Java + фреймворк.

      Ну будет часть бизнес-логики жить в какой-нибудь монаде типа STM, тоже мне проблема. Зато, опыт показывает, значимая часть всё ещё будет чистой, хорошо тестируемой, композируемой и так далее.


      И сравнивать это с джавой — ну такое.


      1. sshikov
        05.02.2019 21:13

        >И сравнивать это с джавой — ну такое.
        Ну, сравнивать-то можно, очего же нет? Я правда вам скажу, что хорошие проекты на Java делаются примерно так же — путем выделения максимально чистой значимой части, убирания стейта, ну то есть примерно теми же средствами, только инструмент при этом не особо помогает.


      1. cblp
        05.02.2019 21:23

        Что не так с порядком действий в Хаскельной do?


        1. 0xd34df00d
          05.02.2019 21:25
          +1

          Система типов не умеет читать мысли и не запретит вам сделать


          do
            updateRecord (\Record { .. } -> ident == 1) (\r -> r { name = "foo" })
            insertRecord Record { ident = 1, name = "meh" }

          и потом удивляться, почему у вас в базе Record { ident = 1, name = "meh" } вместо Record { ident = 1, name = "foo" }.


          1. cblp
            05.02.2019 21:28

            Почему это должно быть запрещено? Может, автор хочет именно то, что здесь написано — сначала update, потом insert?


            1. 0xd34df00d
              05.02.2019 21:29

              Не знаю, почему, но я не могу придумать другую интерпретацию претензии из исходного коммента. Может, Throwable нас рассудит.


              1. cblp
                05.02.2019 21:31
                +3

                Вероятно, автор исходной претензии что-то читал про негарантированный порядок вычислений и не знает, чем вычисление отличается от действия.


                1. Throwable
                  06.02.2019 12:14

                  Т.н. "вычисление" не может достать что-то из БД или не может вызвать системную функцию? И функции внутри функциональной композиции не могут иметь "действия"?
                  Да, я имел ввиду именно негарантированный и вообще неявный порядок вычисления, когда вы делаете сложную композицию из функций, которые внутри содержат некие действия с общим стейтом. И я так думаю, это именно те случаи, которые имел ввиду Игорь Шевнин в своей фразе.


                  1. cblp
                    06.02.2019 13:05
                    +1

                    Т.н. "вычисление" не может достать что-то из БД или не может вызвать системную функцию?

                    Не может (без unsafe).


                    И функции внутри функциональной композиции не могут иметь "действия"?

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


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


                    Да, я имел ввиду именно негарантированный и вообще неявный порядок вычисления, когда вы делаете сложную композицию из функций, которые внутри содержат некие действия с общим стейтом.

                    Вот это как раз невозможно (возможно только если специально стрелять себе в ногу через unsafe). Неявное изменение порядка вычислений есть, но оно не вредит, а либо не имеет значения, либо помогает.


                    И я так думаю, это именно те случаи, которые имел ввиду Игорь Шевнин в своей фразе.

                    Я уверен, что нет. Иногда хочется разобраться в деталях, например, чтобы оптимизировать скорость или расход памяти, и только в этом случае ленивость сложнее императивного кода. Хотя на этот случай есть инструменты управления энергичностью и ST для локального отказа от ленивости в пользу явного управления порядком и присваиваний в обычные изменяемые переменные.


                    1. interphx
                      06.02.2019 15:47

                      Я имел в виду в основном производительность, да. Хотя сформулировал, пожалуй, неудачно. Тут в комментариях 0xd34df00d привёл хороший пример, как производительность алгоритма оказалась обманчивой, потому что сортировались только первые 10 элементов, а не все данные.

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


      1. Throwable
        06.02.2019 13:33

        Основной смысл в разделении эффектов и возможность выразить пусть и императивную предметную область максимально типобезопасно.

        Я очень даже за типы и ненавижу безтиповые языки. Однако ни одна из современных областей знаний, кроме математики, на сегодня не оперирует терминами теории категорий и гомотопической теории типов. Поэтому если внезапно удастся создать Теорию Всего (и описать ее на Хаскеле), скорей всего она так и останется теорией, ибо пользоваться ей будет бесконечно сложно.
        Между прочим сам алгоритм на императивном даже безтиповом языке программирования — это тоже вариант описания предметной области. И далеко не факт, что описание при помощи системы типов будет проще и понятнее самой императивной программы. Как указал один из респондентов, система типов может быть бойлерплейтом.


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

        Ну вот это нифига не показатель. Показателем будет, например, когда весь стек компании (или большое число разнотипных задач) переписали на Хаскель, и стоимость проекта/сроки сдачи уменьшились на столько-то.


        Ну будет часть бизнес-логики жить в какой-нибудь монаде типа STM, тоже мне проблема. Зато, опыт показывает, значимая часть всё ещё будет чистой, хорошо тестируемой, композируемой и так далее.

        Все данные в STM не запихаешь, а чтобы база стала STM, нужен как минимум serializable уровень изоляции. Кроме того, чтобы обеспечить чистоту, вам придется отделить все чтения от всех записей, а такая компоновка не всегда соответствует задаче — все-таки в каждом из бизнес-модулей выполняются сразу как чтения, так и записи.


        1. 0xd34df00d
          06.02.2019 16:13

          Однако ни одна из современных областей знаний, кроме математики, на сегодня не оперирует терминами теории категорий и гомотопической теории типов. Поэтому если внезапно удастся создать Теорию Всего (и описать ее на Хаскеле), скорей всего она так и останется теорией, ибо пользоваться ей будет бесконечно сложно.

          Не понял перехода к Теории Всего, ну да ладно. А вот классификация и типизация вполне себе присуща ежедневным рассуждениям, даже когда вы обсуждаете поход в магазин и покупку каких-то яблок и каких-то стейков, например.


          Ну вот это нифига не показатель. Показателем будет, например, когда весь стек компании (или большое число разнотипных задач) переписали на Хаскель, и стоимость проекта/сроки сдачи уменьшились на столько-то.

          Не понял, почему?


          Все данные в STM не запихаешь, а чтобы база стала STM, нужен как минимум serializable уровень изоляции.

          STM — это один из способов доступа к самой базе, а не к данным внутри базы. Доступом к данным внутри базы заведует сама база, и это уже её внутренняя кухня.


          Кроме того, чтобы обеспечить чистоту, вам придется отделить все чтения от всех записей, а такая компоновка не всегда соответствует задаче — все-таки в каждом из бизнес-модулей выполняются сразу как чтения, так и записи.

          Зачем отделять? Почему в одной транзакции не может быть произвольного набора действий?


          1. Throwable
            07.02.2019 16:25

            А вот классификация и типизация вполне себе присуща ежедневным рассуждениям, даже когда вы обсуждаете поход в магазин и покупку каких-то яблок и каких-то стейков, например.

            Как правило в этом случае задача стоит достаточно конкретно и для ее решения хватает системы типов, предоставляемой типичным ООП-языком. Делал я как-то движок для покера, и подумал, что как раз тут пригодилась бы система типов для вычисления комбинаций. Оказывается, есть реализация на Хаскеле. Принцип более-менее понятен. Однако не могу сказать, что представленная модель сильно напоминает человеческое описание правил игры, а также, что сходный функционал на Java сильно в чем-то уступает.


            Не понял, почему?

            Может это вы оказались хорошим специалистов на фоне остальных, может задача была специфическая и ее эффективнее было решать на Хаскеле, может еще куча причин было. Я не слышал success stories от массового применения Хаскеля в компаниях, почему бы, если он настолько удешевляет разработку?


            Почему в одной транзакции не может быть произвольного набора действий?

            Для примера возьмем абстрактный регистр X и какие-нибудь два вычисления, изменяющие его значения: X := f1(X) и X := f2(X). Не важно какая реализация у X — STM, файл или строка в базе данных. Есть всего два варианта реализации транзакции:


            1. Все чтения X будут выдавать одно и то же значение, которое было на момент начала транзакции, а все изменения X будут видны уже после транзакции.
            2. Все последовательные изменения X будут видны в той же транзакции.

            И оба способа плохие. В первом случае мы сразу получаем проблему "lost update". Во втором случае логика полагается на последовательное применение операций. Но поскольку в нашей функциональной программе последовательность чтений и записей не определена (или определена неявно), то это будет вести к трудноотловимым ошибкам.


            1. cblp
              07.02.2019 16:33
              +1

              Второй вариант хороший. STM его обеспечивает. Поскольку чтение и запись регистра — императивный эффект, Хаскель обеспечивает порядок. Очень плохо, что в вашем языке последовательность чтений из записей не определена. Переходите на Хаскель.


            1. 0xd34df00d
              07.02.2019 17:50
              +1

              Как правило в этом случае задача стоит достаточно конкретно и для ее решения хватает системы типов, предоставляемой типичным ООП-языком.

              Не хватает, картинка.про.паттерны.пнг.


              У вас мультиметоды искаропки в языке? Кто наследуется от кого, квадрат от прямоугольника или прямоугольник от квадрата, вы уже решили? Tagless final вот прям так с пол-пинка строится? Система типов обеспечивает вам гарантию отсутствия нежелательных эффектов в STM-транзакции или в чистой функции? Как там с многопоточностью, опять же?


              И это я просто за 10 секунд нагенерил.


              Оказывается, есть реализация на Хаскеле.
              poker-eval: Binding to libpoker-eval

              Ну вы поняли :]


              Однако не могу сказать, что представленная модель сильно напоминает человеческое описание правил игры, а также, что сходный функционал на Java сильно в чем-то уступает.

              С учётом вышесказанного — неудивительно.


              Может это вы оказались хорошим специалистов на фоне остальных

              Так, может, я оказался потому, что пользовался правильным инструментом?


              Я не слышал success stories от массового применения Хаскеля в компаниях, почему бы, если он настолько удешевляет разработку?

              Потому что хаскелистов мало :(


              Для примера возьмем абстрактный регистр X и какие-нибудь два вычисления, изменяющие его значения: X := f1(X) и X := f2(X).

              Ну так никто не мешает их вот прям так вот вызвать подряд в одной STM-транзакции и получить второй вариант.


          1. Druu
            08.02.2019 07:34
            -1

            А вот классификация и типизация вполне себе присуща ежедневным рассуждениям, даже когда вы обсуждаете поход в магазин и покупку каких-то яблок и каких-то стейков, например.

            Им присуща как раз динамическая типизация :)
            То есть тип яблок как объекта, в рантайме, но не тип терма.


            Tagless final

            Кривой костыль для языков, в которые нормальных макросов не завезли ;)


    1. Doctor_Ryner
      05.02.2019 23:35

      > В ООП мире моделируется система сущностей, наиболее приближенная к реальному миру
      1. Несовершенный мир
      2. Идеализированная математическая модель
      Хм… логичный выбор. Проблема в том, что эти «сущности» помещены не в реальный мир, а в никуда и просто взаимодействуют между собой побочными эффектами мутируя все подряд, моделируя приближённый к миру хаос и непредсказуемость. Насчет JS, зачем у вас там в React то иммутабельность привносят? А TypeScript и Flow? От хорошей жизни? Нормально они без типов живут (в Python вообще типы добавили), ага, достаточно спросить в чате какого это поддерживать JS приложение без типов и тестов… с тестами для тестов, вот это то конечно лучше.

      Насчет IO, начнем с того, что мягко говоря многие вместо написания чистых иммутабельных функций будут писать мутабельный код с побочными эффектами, в хаскеле же напротив, IO используется исключительно только в тех случаях, когда без него просто никак. Всякие вещи на подобии взаимодействия с базами данных отделяются и отчищаются, смысл в том, что бы контролировать побочные эффекты, хаскель поощряет использование чистых функций, поэтому опять же, человек будет максимально часто писать чистый код, на других же языках обычно с этим не заморачиваются, пихнут стейта, ссылок, указателей, «не дай бог», глобальных переменных, и начинают мутировать друг друга


      1. Throwable
        06.02.2019 14:20

        Проблема в том, что эти «сущности» помещены не в реальный мир, а в никуда и просто взаимодействуют между собой побочными эффектами мутируя все подряд, моделируя приближённый к миру хаос и непредсказуемость.

        Сущности — это лишь компоновка общего стейта, которая может отличаться для различных парадигм. Не важно чем он представлен — записями, объектами, переменными, таблицами в базе. Весь стейт мутирует всегда предсказуемо при последовательном применении операций, что отвечает интуитивной концепции времени. В каждый момент у нас есть стабильный snapshot всей нашей вселенной. Когда речь заходит о паралельном программировании, и нарушается sequential consistency, то все-равно так или иначе всю задачу стремятся свести к последовательному выполнению, изолируя области данных (например стек) и используя уже избитые примитивы синхронизации.
        Да, ООП далеко не самая лучшая парадигма, и большинство фреймворков предлагает обычное процедурное программирование даже в ООП-языках, разделяя stateful и stateless объекты.


        Всякие вещи на подобии взаимодействия с базами данных отделяются и отчищаются, смысл в том, что бы контролировать побочные эффекты, хаскель поощряет использование чистых функций

        Как я уже писал выше, это предполагает определенную компоновку бизнес логики: т.е. мы отделяем все чистое и вычислимое от всего грязного и "эффектного". Хорошо, если у нас более-менее однородная задача, и она вся легко перекомпонуется — все эффекты, например, можно свалить вконец операции. Но это не всегда подходит для сложных бизнес-задач, которые состоят из множества других атомарных модулей, каждый из которых содержит как вычисление, так и действие.


  1. JC_IIB
    05.02.2019 20:33

    del


  1. Druu
    05.02.2019 20:54

    Она может увеличить производительность, если результаты промежуточных вычислений не будут использоваться. (К примеру head. sort работает за линейное время).

    А это сам sort за квадрат тогда работает, что ли?


    1. 0xd34df00d
      05.02.2019 20:59

      Зачем? Это просто вырождается в partial sort за счёт ленивости.


      1. Druu
        05.02.2019 21:11
        +1

        Зачем? Это просто вырождается в partial sort за счёт ленивости.

        Очевидно, это верно не для любого алгоритма. Например, если это квиксорт, то чтобы взять от него head — надо, с-но, выполнить весь квиксорт, целиком


        Вот я попытался вспомнить какую-нибудь неквадратичную сортировку, которая в ленивом случае бы выродилась в линейный head, и не смог. Потому и вопрос.


        1. 0xd34df00d
          05.02.2019 21:18
          +1

          Очевидно, это верно не для любого алгоритма.

          Да, но на практике конкретно для sort верно (и при этом sort — O(n logn)).


          Я, кстати, так прикольно обжёгся как-то несколько лет назад, когда для курсеровского курса по биоинформатике запрогал Барроуза-Уиллера, и для теста сделал take 10 вместо вывода всего результирующего списка, и работало у меня оно адски быстро. Пришёл в один чатик по C++, похвастался, а потом до меня дошло, что сортировал я в итоге только первые 10 элементов.


          Например, если это квиксорт, то чтобы взять от него head — надо, с-но, выполнить весь квиксорт, целиком

          Совсем неочевидно. Пусть у нас (да, не совсем квиксорт, но пофиг)


          quicksort [] = []
          quicksort (x:xs) = small ++ large
            where small = quicksort [y | y <- xs, y <= x]
                  large = quicksort $ x : [y | y <- xs, y > x]

          Чтобы взять первый элемент, мне нужно амортизированно взять только первый элемент small, вычислять large мне не нужно совсем. А далее рекурсивно.


          1. vvadzim
            06.02.2019 13:06

            Прошу прощения, я не хаскелист, но разве оно не зациклится в последней строчке, если список начинается с минимального элемента?


            1. 0xd34df00d
              06.02.2019 16:13

              Да, вы правы, конечно (и на самом деле оно там зациклится вообще всегда).


        1. cblp
          05.02.2019 21:25

          Во стандартной библиотеке Хаскеля сортировка пирамидальная.


  1. math_coder
    06.02.2019 01:32
    +1

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

    Теперь я переписываю всё с Haskell'а на Rust. Многое уже переписал, всё летает (с тем же алгоритмом и без какой-либо оптимизации).

    Обращаясь ко всем, хочу сказать следующее. Люди! Haskell — это прекрасно! Учить его полезно любому! Но если вы, как я, поймёте, что не осилили, — не расстраивайтесь: Haskell правда сложный и правда не для всех; я проверил.


  1. VioletGiraffe
    06.02.2019 09:06

    C++ даже сравнивать ни с чем не надо, язык ужасен. Си — хороший язык для низкоуровневой разработки.

    Всё ясно с этими товарищами. После этой фразы интерес к мнению этого человека упал до нуля.


  1. ne_zabudka
    06.02.2019 10:34

    Джон Доу: Строгая сильная (я бы сказал, фашистская) типизация.

    На сколько я знаю, он же православный!


  1. avrilfanomar
    06.02.2019 14:26

    Лично мне, после знакомства с ООП откровенно «сломать голову» пришлось при ознакомлении именно с Prolog (declarative) нежели чем с Haskel или Lisp (functional). Я считаю, что нужно просто сначала понять парадигму, а потом начинать учить язык.
    Всегда удивлял спор о том, что ООП лучше ФП и т.п., так как любой иструмент удобен там, куда он предназначен. Жарить в кастрюле тоже возможно, но не всегда оправдано :)


  1. barsuksergey
    06.02.2019 16:44
    +1

    После того как Ares_ekb опубликовал свою статью про теорию категорий, я потерял покой и сон и нашёл Голдблатта «Топосы. Категорный анализ логики». Это не книга, нет. Это борьба и торжество духа.
    А после прочтения коллегой книги по Haskell стало понятно — язык очень хорош для качественного скачка компетентности программиста. Он даёт особый взляд, особое видение и на саму проблему, и на множество её решений. И даже если ни одно решение не получится сделать на ФП (а в мире JS, Go и PHP это часто бывает...), вы ничего не потеряете, но приобретёте многое. За которое в будущем вас будут уважать, платить заработную плату и приглашать на конференции. Не знаю, как это влияет на чсв, а вот на настроение влияет положительно )))


    1. Druu
      06.02.2019 16:52

      я потерял покой и сон и нашёл Голдблатта «Топосы. Категорный анализ логики»

      Для начинающих — плохая книга, автор достаточно безалаберно относится к строгости изложения.


      1. barsuksergey
        06.02.2019 17:04

        Мне пока не с чем сравнить. Если есть хорошие (для начинающих) по теории категорий — делитесь, пожалуйста.


        1. Druu
          06.02.2019 17:41

          "категории для работающего математика" Маклейна, тут без вариантов. В принципе, достаточно первых 5 глав (с решением задачек, конечно).
          А Голдблатт — он интересный, но желательно его читать, уже имея хорошее представление о предмете.


          1. 0xd34df00d
            07.02.2019 00:38

            Мне от неё припекает, там всё время отсылки к другим областям математики типа топологии, в которых я не очень шарю, и от которых я всё время чувствовал себя дном.


            1. Druu
              07.02.2019 06:57

              Мне от неё припекает, там всё время отсылки к другим областям математики типа топологии, в которых я не очень шарю, и от которых я всё время чувствовал себя дном.

              Ну теоркат без отсылок смысла не имеет, он же сам по себе бессодержателен. Да и отсылки там не требуют более чем базовых знаний.


        1. math_coder
          06.02.2019 18:54

          Кое-какие начальные сведения о категориях есть "Не совсем наивной теории множеств" Вавилова (но там надо читать всё подряд, так что если теория множеств не интересует, то видимо это не вариант).


          Ещё вот — Написал учебник теории категорий


          1. barsuksergey
            07.02.2019 12:59

            Вы — автор?

            Заключительная мысль: теория категорий не является древним знанием, смысл которого утрачен – это живая и тёплая наука.
            — хорошая мысль. И учебник интересный, берём на вооружение.


            1. math_coder
              07.02.2019 16:45

              Вы — автор?

              Нет, я просто завсегдатай и активный участник dxdy.ru.


        1. al_mo
          06.02.2019 21:56

          я тоже в ФП начинающий, читаю вот эту книгу: Category Theory for Programmers
          Объяснения понятные, примеры разбираются на Хаскеле и С++


        1. artemisia_borealis
          07.02.2019 18:49

          Неретин Ю. А. "Категории симметрий и бесконечномерные группы".

          краткое описание
          Книга содержит систематическое изложение теории бесконечномерных групп, их представлений, а также полугрупповых и категорных оболочек. Подробно рассматриваются группа диффеоморфизмов окружности, бесконечномерные аналоги классических групп, группы преобразований пространств с мерой и некоторые группы токов. Обсуждаются также бесконечные аналоги симметрических групп и группы петель. Ряд разделов книги посвящен связанным с конечномерными группами Ли явлениям, которые стали известны лишь благодаря появлению теории бесконечномерных групп. Изложение основано на категорной версии метода вторичного квантования. Для математиков и математических физиков, так или иначе имеющих дело с бесконечномерными группами, а также студентов и аспирантов соответствующих специальностей.


          1. Druu
            08.02.2019 07:49

            он располагает категории на том же "уровне абстракции".

            А что в случае такого подхода происходит, когда совокупность объектов/морфизмов не является множеством?


  1. eugenk
    08.02.2019 06:27
    +1

    Народ, заранее прошу прощения за возможно ламерский вопрос, но никто не подскажет хорошей IDE под хаскель? Чего-то подвигла меня эта статья на его изучение. Давно уже хотелось, но как-то было не до того. А сейчас почувствовал что пора, хотя в настоящее время сильно занят. Да и внука-оболтуса пора к делу припахивать. Не с С++ же с ним начинать!


    1. a_e_tsvetkov
      08.02.2019 06:57
      +1

      Я знаю два варианта:
      1. Плагины к эклипсу.
      2. leksah

      Оба рабочие, но оба не то чтобы слишком юзерфрендли. Я остановился на последнем, но по сравнению с IDE для Java это зачастую боль и страдание.

      PS: если вы пользуетесь emacs, то для вас есть еще варианты, но я их в живую не видел.


    1. nexmean
      08.02.2019 07:16
      +1


      HIE очень нестабилен, способен жрать очень много памяти, зато фичастый.
      Ghcid наоборот же работает весьма стабильно и без особых проблем с производительностью, но фич у него минимум.


    1. cblp
      08.02.2019 10:20

      В нашем большом сообществе ruHaskell есть вики для ответов на такие часто задаваемые вопросы github.com/ruHaskell/ruhaskell/wiki


      1. a_e_tsvetkov
        08.02.2019 13:37

        У гитхаба нет поиска по вики. Как этим пользоваться?


        1. cblp
          08.02.2019 14:56

          Поиск по вики есть — https://github.com/ruHaskell/ruhaskell/search?q=IDE&type=Wikis


          Хотя там всего несколько страниц, можно по их списку пройтись.


          А ещё можно задавать вопросы в наших чатах — https://ruhaskell.org/links.html


    1. nexus478
      08.02.2019 12:35
      +1

      Есть плагины для IntelliJ IDEA, Visual Studio Code, Sublime, Atom, Vim, Emacs. Тут уж на ваш вкус.


    1. develop7
      08.02.2019 15:46

      Можно взять просто лучшую в мире (кроссплатформенную) IDE Jetbrains IDEA и поставить в неё plugins.jetbrains.com/plugin/8258-intellij-haskell


  1. molnij
    08.02.2019 14:13

    Скажите, а как сочетается

    Не стоит забывать, что еще лет 20 назад железо было не достаточно производительным для функциональных языков, так что в мейнстрим функциональщина начала входить в последние годы, а интерес к Haskell только растет.

    и
    Денис Мирзоев: По скорости сравним с Java, но не такой быстрый как C.

    То есть для Java двадцать лет назад производительности хватало, а для Хаскеля было мало?
    Тут правда еще вопрос к 20 годам, потому что разница в производительности например Pentium II выпущенного 21 год назад и Pentium 4 (Northwood) — 17 лет назад была колоссальной


    1. cblp
      08.02.2019 14:58
      +1

      20 лет назад хаскельные компиляторы оптимизировали хуже, чем Ява.