Я знаю людей, которые искренне недоумевают по поводу того, что функциональное программирование не очень популярно. К примеру, сейчас я читаю книжку «Из смоляной ямы» (Out of the Tar Pit), в которой авторы после аргументов в пользу функционального программирования говорят:

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

А я думаю, что причина недостаточной популярности намного проще: программирование в функциональном стиле часто происходит «задом наперед» и выглядит больше как решение головоломок, чем объяснение задачи компьютеру. Часто, когда я пишу на функциональном языке, я знаю, что хочу сказать, но в итоге я решаю головоломки, чтоб выразить это средствами языка. Короче, функциональное программирование просто слишком неестественное.

Чтоб дальше обсуждать функциональное программирование, давайте попробуем испечь пирог. Возьмем рецепт отсюда. Примерно так мы будем печь императивный пирог:
  1. Разогрейте духовку до 175°C. Смажьте маслом и посыпьте мукой противень. В маленькой миске смешайте муку, пищевую соду и соль.
  2. В большой миске взбивайте масло, сахар-песок и коричневый сахар до тех пор, пока масса не станет легкой и воздушной. Вбейте яйца, одно за раз. Добавьте бананы и разотрите до однородной консистенции. Поочередно добавляйте в получившуюся кремовую массу основу для теста из п. 1 и кефир. Добавьте измельченные грецкие орехи. Выложите тесто в подготовленный противень.
  3. Запекайте в разогретой духовке 30 минут. Выньте противень из духовки, поставьте на полотенце, чтоб пирог остыл.

Я позволил себе несколько вольностей с нумерацией (очевидно, каждый шаг—это на самом деле несколько шагов), но давайте лучше посмотрим, как мы будем печь функциональный пирог:
  1. Пирог—это горячий пирог, остывший на полотенце, где горячий пирог—это подготовленный пирог, выпекавшийся в разогретой духовке 30 минут.
  2. Разогретая духовка—это духовка, разогретая до 175°C.
  3. Подготовленный пирог—это тесто, выложенное в подготовленный противень, где тесто—это кремовая масса, в которую добавили измельченные грецкие орехи. Где кремовая масса—это масло, сахар-песок и коричневый сахар, взбитые в большой миске до тех пор, пока они не стали легкими и воздушными, где…

А, ну его к черту—я не могу это закончить! (прим. перев. на самом деле, если следовать логике, даже приведенные пункты должен быть еще сложнее). Я не знаю, как перенести эти шаги в функциональный стиль без использования изменяемого состояния. Либо теряется последовательность шагов, либо надо писать «добавьте бананы», но тогда изменяется текущее состояние. Может, кто-нибудь в комментариях закончит? Хотелось бы посмотреть на версии с использованием монад и без использования монад.
В комментариях к оригинальноей статье предложили несколько вариантов
С монадами не было, но было с и без pipe forward operator.

Без использования pipe forward operator:
cake = cooled(removed_from_oven(added_to(30min, poured(greased(floured(pan)), stirred(chopped(walnuts),
alternating_mixed(buttermilk, whisked(flour, baking soda, salt), 
mixed(bananas, beat_mixed(eggs, creamed_until(fluffy, butter, white sugar, brown sugar)))), 
preheated(175C, oven))))))

C использованием pipe forward operator:
cake = bake(cake_mixture, 30min, prepare(pan, (grease, flour)), preheated(175C, oven))
where cake_mixture =
creamed :until_fluffy ‘butter’ ‘white’ ‘sugar’ ‘brown sugar’
|> beat_mixed_with ‘eggs’
|> mixed_with ‘bananas’
|> mixed_with :alternating ‘buttermilk’ ‘dry_goods’
|> mixed_with chopped ‘walnuts’
where dry_goods = whisked ‘flour’ ‘baking soda’ ‘salt’


У императивных языков-таки есть огромное преимущество в том, что у них есть неявное состояние. И люди, и машины очень хорошо работают с неявным состоянием, привязанным ко времени. Когда вы читаете рецепт пирога, вы знаете, что после выполнения первой инструкции духовка разогрета, противень смазан и мы замесили основу для теста. Это не нужно явно описывать. У нас есть инструкции и мы знаем, что конечное состояние получится путем выполнения этих инструкций. Императивный рецепт никого не поставит в тупик. А если бы мне удалось закончить функциональный рецепт и если бы я показал его моей маме, она была бы им, наверное, очень сильно озадачена. (Ну как минимум версией без монад. Может быть, версия с монадами не так сильно сбивала бы с толку.)

Я пишу этот пост, потому что столкнулся недавно с похожей проблемой. Так уж оказалось, что шаблоны С++ — это функциональный язык. И когда разработчики С++ это поняли, то вместо того, чтоб решить проблему, стали всячески лелеять шаблоны в функциональном стиле, что иногда делает переписывание обычного кода через шаблоны очень утомительным. Например, вот что я недавно написал для парсера. (Я знаю, глупо писать свой собственный парсер, но старые тулзы типа yacc и bison плохие, а когда я попробовал пользоваться boost spirit, то столкнулся с проблемами, решение которых занимало слишком много времени, и в конце концов я просто решил написать свой парсер.)
ParseResult<V> VParser::parse_impl(ParseState state)
{
    ParseResult<A> a = a_parser.parse(state);
    if (ParseSuccess<A> * success = a.get_success())
        return ParseSuccess<V>{{std::move(success->value)}, success->new_state};
    ParseResult<B> b = b_parser.parse(state);
    if (ParseSuccess<B> * success = b.get_success())
        return ParseSuccess<V>{{std::move(success->value)}, success->new_state};
    ParseResult<C> c = c_parser.parse(state);
    if (ParseSuccess<C> * success = c.get_success())
        return ParseSuccess<V>{{std::move(success->value)}, success->new_state};
    ParseResult<D> d = d_parser.parse(state);
    if (ParseSuccess<D> * success = d.get_success())
        return ParseSuccess<V>{{std::move(success->value)}, success->new_state};
    return select_parse_error(*a.get_error(), *b.get_error(), *c.get_error(), *d.get_error());
}

Эта функция парсит входной параметр в variant type типа V, пытаясь запарсить входной параметр как тип A, B, C или D.
прим. перев.
Если я правильно понимаю, в этом контексте термин variant type значит примерно «размеченное объединение/алгебраический тип данных», и действительно: V может быть либо A, либо B, либо C, либо D. Такое значение есть и в википедии (последний параграф перед оглавлением).
В реальном коде имена у этих типов получше, но они для нас не важны. В этом примере есть очевидная дупликация: мы четыре раза выполняем совершенно одинаковый фрагмент кода с четырьмя разными парсерами. C++, в общем-то, по-настоящему не поддерживает монады, но можно было бы сделать этот фрагмент кода переиспользуемым, написав цикл, который бы перебирал все четыре парсера по порядку:
template<typename Variant, typename... Types>
ParseResult<Variant> parse_variant(ParseState state, Parser<Types> &... parsers)
{
    boost::optional<ParseError> error;
    template<typename T>
    for (Parser<T> & parser : parsers)
    {
        ParseResult<T> result = parser.parse(state);
        if (ParseSuccess<T> * success = result.get_success())
            return ParseSuccess<Variant>{{std::move(success->value)}, success->new_state};
        else
            error = select_parse_error(error, *result.get_error());
    }
    return *error;
}
ParseResult<V> VParser::parse_impl(ParseState state)
{
    return parse_variant<V>(state, a_parser, b_parser, c_parser, d_parser);
}

Этот код чуть-чуть неоптимален, потому что надо выбирать нужное сообщение об ошибке, но в целом это довольно тривиальная трансформация исходного примера. За исключением того, что вы не можете написать так на С++. Как только в игру вступают шаблоны, вам нужно думать более функционально. Вот мой вариант:
template<typename Variant, typename First>
ParseResult<Variant> parse_variant(ParseState state, Parser<First> & first_parser)
{
    ParseResult<First> result = first_parser.parse(state);
    if (ParseSuccess<First> * success = result.get_success())
        return ParseSuccess<Variant>{{std::move(success->value)}, success->new_state};
    else
        return *result.get_error();
}
template<typename Variant, typename First, typename... More>
ParseResult<Variant> parse_variant(ParseState state, Parser<First> & first_parser, 
    Parser<More> &... more_parsers)
{
    ParseResult<First> result = first_parser.parse(state);
    if (ParseSuccess<First> * success = result.get_success())
        return ParseSuccess<Variant>{{std::move(success->value)}, success->new_state};
    else
    {
        ParseResult<Variant> more_result = parse_variant<Variant>(state, more_parsers...);
        if (ParseSuccess<Variant> * more_success = more_result.get_success())
            return std::move(*more_success);
        else
            return select_parse_error(*result.get_error(), *more_result.get_error());
    }
}
ParseResult<V> VParser::parse_impl(ParseState state)
{
    return parse_variant<V>(state, a_parser, b_parser, c_parser, d_parser);
}

И я, честно говоря, очень доволен этим вариантом. Конечно, это тяжелее читать, потому что итерирование скрыто теперь в рекурсии, но если б вы только видели мой код до того, как я придумал это решение… У меня была структура с полем std::tuple<std::reference_wrapper<Parser>…>. Если вы когда-нибудь работали с кортежем переменной длины из стандартной библиотеки (то бишь variadic sized std::tuple), вы должны знать, что одно это превращает любой код в ребус.

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

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

С учетом всего вышесказанного, считаю ли я, что функциональные языки плохие? Вовсе нет. Польза от функциональных языков совершенно осязаемая. Каждый должен выучить хотя бы один функциональный язык и пробовать применять полученные знания в других языках. Но если функциональные языки хотят стать популярными, они должны быть меньше связаны с разгадыванием ребусов.
Поделиться с друзьями
-->

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


  1. Saffron
    16.06.2016 02:50
    +2

    Головоломки — не самое страшное, к ним можно притерпеться. Я достаточно быстро обнаружил, что не могу собрать сложный проект из маленьких частей на хаскеле. ООП даёт средства для декомпозиции, а хаскель — нет. Ну и проблемы с производительностью. Все виденные мною реальные применения хаскеля приходили к тому, что используется прямой доступ к памяти, глобальное состояние и строгие алгоритмы. Хаскель давит своей идеологией абсолютной чистоты, но чистота эта встречается лишь в мелочах.


    1. VoidEx
      16.06.2016 10:13
      +10

      Хаскель даёт средства декомпозиции — функции


    1. mad_celt
      16.06.2016 10:19

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


      1. graninas
        16.06.2016 11:31
        +4

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

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


        1. eugzol
          17.06.2016 21:40
          +1

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

          Включая данное. Пардон, не удержался :)


      1. kmikeru
        16.06.2016 11:42
        +2

        Это сейчас серьёзно было?
        www.haskell.org/onlinereport/preface-jfp.html
        The committee's primary goal was to design a language that satisfied these constraints:
        It should be suitable for teaching, research, and applications, including building large systems.


        1. ganqqwerty
          16.06.2016 15:26
          +6

          ну так это они описывают то, что хотели, а не то, что получилось


          1. kmikeru
            16.06.2016 15:43

            Читаем ещё раз тезис «той области, для которой был создан — в теории категорий». По ссылке сказано, что это, мягко говоря, не так.


            1. ganqqwerty
              16.06.2016 16:14
              +2

              Ваша правда, может они и создавали его не только для академических проектов. Но гляньте на список авторов — там же сплошная академия, всего один человек от индустрии. Академики пишут академические проекты, говорю как участник одного из них.


    1. potan
      16.06.2016 15:56
      +1

      А в чем проблема со сборкой?
      Для немонадических «маленьких частей» все вообще очевидно. Композиция функций с возможным добавлением прослоек с преобразованиями типов.
      С монадическими или стрелочными «частями» надо смотреть. Если монады не покидают границ модуля, как в первом случае. Если это простая монада, которую можно «запустить» (типа парсера), тоже обычно все просто. Если там IO или STM, то применять их можно только в другом монадическом коде — но это получается мало отличается от обычного императивного программирования.


    1. potan
      16.06.2016 15:58

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


      1. Flammar
        16.06.2016 16:00
        +1

        И отлаживать ленивость труднее…


        1. potan
          16.06.2016 17:59
          +1

          Мне очень мало приходилось отлаживать программы Haskell — если они компилировались, почти всегда работали.
          А вот привычка к ленивости при переходе на C++ и Scala принесла необходимость отлаживать инициализацию взаимозависимых объектов. В ленивом языке с этим было проще.


        1. 0xd34df00d
          17.06.2016 04:22
          +1

          Отлаживать как раз проще, с таким-то repl'ом.

          Я тут переписывал прототип с хаскеля на плюсы — очень страдал по этому поводу.


      1. 0xd34df00d
        17.06.2016 04:32
        +11

        У меня был код, который загружал архив новостей, делал токенизацию, некоторые преобразования (от HTML-тегов почистить там, это всё), дёргал NLP.Snowball для стемминга, а потом полученное интернировал (заменял токены на их уникальные Int32-идентификаторы, дабы памяти меньше жралось и вообще SVM потом на это дело натравить можно было, например). Ну, да и всё, я хотел просто посмотреть, что из этого получится, и дальше плясать от данных.

        В общем, работало оно, скажем, 60 минут на тестовом датасете.

        Я попрофилировал, увидел, что gc дохрена жрёт. Поковырял heap profile, -hc, это всё, повставлял строгости где надо, где надо вообще force сделал, стало жраться 20 минут.

        Я подумал, что это много, попрофилировал, увидел, что много времени жрётся в интернировании в чисто функциональной Data.HashMap.Strict. Ну я ж не лыком шит, у меня есть Data.HashTable, живущее в ST, поэтому я хорошенько обдолбался и переписал этот код так, чтобы оно всё завернулось в ST (на самом деле в произвольную монаду m, Identity для старого Data.HashMap и ST s для нового Data.Hashtable), заодно ментально поонанировал на {-# LANGUAGE FunctionalDependencies #-} (ну серьёзно, чувствую себя прям на острие прогресса, когда пишу конкретно эту прагму), а то иначе тайпчекер не был доволен связью m с остальным кодом, и оно стало работать, ну, скажем, 9 минут.

        9 минут — это тоже много, поэтому я попрофилировал ещё, увидел, что 60% времени жрётся в стемминге, остальное размазано ровным слоем, и погрустнел, потому что реальные объёмы данных планировались на пару порядков больше.

        Потом через пару недель у меня дошли руки переписать всё на плюсах. Ну, в общем, на плюсах оно 20 секунд работает. Включая стемминг в том же snowball. Хотя байтики ручками в std::string двигать приходится, конечно, это да, да и писать на boost.spirit больнее, чем на attoparsec.


  1. Aetet
    16.06.2016 08:59
    +31

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

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

    class NumericOperation {
      NumberState state;
      NumericOperation(this.state);
      add() {
        return state.a + state.b;
      }
    }
    
    class NumberState {
      int a;
      int b;
    }
    


    Таким образом все состояние над которым мы производим операции можно протестировать, потому что мы его задаем только в конструкторе. Легко пользоваться моками. И да, несмотря на то, что NumericOperation хранит ссылку на состояние это не мешает нам писать в ФП стиле. Ведь функция add — чистая.

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


    1. Aetet
      16.06.2016 09:04
      +1

      Таким образом мы можем добавить еще несколько состояний при этом даже не нарушив внешний контракт при условии, что мы возвращаем корректно значение:

      class NumericOperation {
        NumberState state;
        StringState stringState;
        NumericOperation(this.state, this.stringState);
        add() {
          return state.a + state.b + parseToInt(stringState.c);
        }
        parseToInt(String c) {
          // логика парсинга
         return someNumber;
        }
      }
      


      Ведь за проброску данных отвечает DI и нам достаточно поправить вызов DI, а не копаться в тонне копипасты в коде, где используется new NumericOperation.


    1. ApeCoder
      16.06.2016 09:31

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

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


      1. Aetet
        16.06.2016 09:41

        Собственно у нас так и есть. Все состояние лежит в NumberState.
        Пусть читает данные кто хочет. Лишь бы не писали.

        Однако немного модифицируем пример, чтобы обеспечить более строгую изоляцию:

        class NumberState {
          int get a;
          int get b = 10;
          setA(int a) {
            this.a = a;
          }
        }
        


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

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


        1. ApeCoder
          16.06.2016 10:01
          +1

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


          1. VolCh
            16.06.2016 10:25
            +1

            Разделить данные и изменяющие их функции (не изменяющие функции в общем случае лучше оставить с данными) — наиболее простой способ обеспечить отсутствие неявных изменений данных. Грубо, если мы вызываем какие-то методы объекта класса SomeObject, то можем быть уверенны, что они не изменяют его состояния, а если вызываем методы объекта класса SomeObjectManager, то уверены, что изменяют (или создают/удаляют).


            1. optimizer
              20.06.2016 15:04

              а как же инкапсуляция, ведь когда-то девизом ООП было «данные+функции».


              1. develop7
                20.06.2016 21:36

                не работает именно поэтому:

                I think the lack of reusability comes in object-oriented languages, not functional languages. Because the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.
                If you have referentially transparent code, if you have pure functions — all the data comes in its input arguments and everything goes out and leave no state behind — it’s incredibly reusable.
                © Joe Armstrong, «Coders at Work»


              1. VolCh
                21.06.2016 05:57

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


      1. VolCh
        16.06.2016 10:14
        +1

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


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


        1. ApeCoder
          16.06.2016 10:24
          +2

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


          1. VolCh
            16.06.2016 10:42

            Сейчас вы говорите уже и не о инкапсуляции, и не о сокрытии, а о замене реализации — это совсем другой вопрос. Сокрытие по сути решает лишь одну задачу — отделение публичного интерфейса от внутреннего. Но эту задачу можно, как правило, решить множеством способов. Но в общем случае ни один из них не гарантирует, что пользователи не будут затронуты — очень часто они рассчитывают не только на формальную сигнатуру интерфейса, но и на определенное поведение, например, что после вызова setA(5), getA() будет возвращать 5, а не 0 или 100500.


            1. ApeCoder
              16.06.2016 12:01
              +1

              Это вопрос в определении контракта.


              1. VolCh
                16.06.2016 15:01

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


                1. ApeCoder
                  16.06.2016 15:37
                  +1

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


                  1. VolCh
                    16.06.2016 18:16

                    Сокрытие реальной структуры состояния в общем случае ортогонально контракту. Если мы не описали в контракте какую-то важную переменную, то будь она хоть глобальной, не говоря о публичной, то никто ей не имеет права трогать. Принцип контрактного программирования: всё, что не разрешено (не описано в контракте) — запрещено. Это с одной стороны. А с другой, я могу описать в контракте приватную переменную и рекомендовать её получать/изменять через отражения, прямой доступ к памяти и т.п.


                    1. ApeCoder
                      16.06.2016 18:36
                      -1

                      Побольше вам таких контрактов :)!


        1. napa3um
          16.06.2016 10:43

          Это была трактовка не инкапсуляции, а, скорее, CQRS.


    1. Bas1l
      16.06.2016 12:27
      +15

      Статья, на мой взгляд—в первую очередь попытка рефлексии на тему того, почему же ФП непопулярно. Потому что по объективным критериям функциональные языки, действительно, совсем не популярны. Хотя, как и написано во вступлении, считается, что у них куча преимуществ. Действительно, и следить за состоянием легко, и параллелить как бы легко, и математически красивые и т.п. Но на них никто не пишет. Взять, к примеру, TIOBE index (конечно, он не совершенен, но хоть какой-то). В первой двадцатке нет ни одного функционального языка. И идея автора показалась мне очень хорошей, и пример с пирогом метким. Да, действительно, судя по всему, функциональные языки просто слишком далеки (i) от моделей реального мира, (ii) от моделей задач, что появляются в головах программистов, и (iii) от того, как работает компьютер. Что изменяемое состояние—это то, что близко реальному миру, человеку, компьютеру.

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

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

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

      P.S. Я не спорю с тем, что какие-то общие и частные идеи из ФП, безусловно, полезны. Стараться писать чистые фунции, не изменять лишний раз состояние. Pattern matching, опять же. Но _иногда_ нарушить правила ФП намного удобнее и лучше, чем пытаться не нарушать. Стандартный пример—циклы. Писать их через рекурсию—мука. Как только у вас будет массив (список!) NumberState, с которыми надо что-то сделать в чистом ФП—все, пиши пропало. А если еще и операций будет несколько, тоже в списке…

      P.P.S. Наконец, в статье не сравнивается ФП и ООП, а скорее ФП и императивное программирование.


      1. napa3um
        16.06.2016 12:36
        -2

        В реальных прикладных задачах места для функционального моделирования предметной области полно, но не каждый проект дорастает до сложности, вынуждающей нести издержки по «решению головоломок ФП» (пока их не превысят потенциальные преимущества в плане управления сложностью всего проекта). Разработчики хеловорлдов постоянно будут критиковать строителей космических кораблей за их переусложнённые подходы (ввиду непонимания первыми проблем последних).


        1. atc
          16.06.2016 15:07
          +4

          Не могу согласиться, в большей части «космических кораблей» разработчики стараются придерживаться максимально простых решений. Пример тому — ядро linux (даже с++ не рискуют брать, не говоря уже о фп языках), openJDK, postgres, каждый из вышеперечисленных проектов решает сложнейшие задачи, но написан почему-то во вполне императивной парадигме.

          В качестве контраргумента могу предложить перечислить крупные opensource проекты, которые написаны преимущественно с fp подходом.


          1. napa3um
            16.06.2016 15:12
            -5

            «Любая достаточно сложная программа на C или Фортране содержит заново написанную, неспецифицированную, глючную и медленную реализацию половины языка Common Lisp.»


            1. atc
              16.06.2016 15:17
              +6

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


              1. napa3um
                16.06.2016 15:23
                -9

                У вас всё ещё впереди. Это моё мнение, не стОит пытаться выпрашивать формальный «пруф», можете не принимать моё мнение или принимать противоположное моему — ваше право.


            1. napa3um
              18.06.2016 14:56
              +2

              When I find my code in tons of trouble,
              Friends and collegues come to me,
              Speaking words of wisdom:
              «Write in C».

              As the deadline fast approaches,
              And bugs are all I can see,
              Somewhere, someone whispers:
              «Write in C».

              Write in C, write in C,
              Write in C, write in C,
              LISP is dead and buried,
              Write in C.

              ( https://www.youtube.com/watch?v=wJ81MZUlrDo )


      1. VoidEx
        16.06.2016 13:12
        +4

        Как только у вас будет массив (список!) NumberState, с которыми надо что-то сделать в чистом ФП—все, пиши пропало. А если еще и операций будет несколько, тоже в списке…

        А можно развернуть, какие возникнут проблемы? Мне, хорошо знакомому с Haskell, совсем неочевидно


      1. VolCh
        16.06.2016 15:04
        +1

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


        Смотря какая цель обучения. Если человек успешно пройдёт такой базовый курс, то с императивными языками точно разберётся.


      1. VolCh
        16.06.2016 15:05
        +1

        Как только у вас будет массив (список!) NumberState, с которыми надо что-то сделать в чистом ФП—все, пиши пропало.

        Что? Отфильтровать, свернуть, отразить?


      1. staticlab
        16.06.2016 20:08

        На седьмой позиции JavaScript. Конечно, он не полностью ФП, но в последние годы на нём стало удобно и модно писать исключительно в функциональном стиле. По сути, полноценный SPA-фронтенд вполне можно написать, например, на React/Redux, пользуясь только функциональными инструментами с точностью до вызова ReactDOM.render(). Отсюда превосходная отлаживаемость и тестируемость. Возражения по поводу циклов тоже непонятны: map, reduce, forEach, filter чем не подходят?


        1. taujavarob
          16.06.2016 21:04
          +1

          staticlab > По сути, полноценный SPA-фронтенд вполне можно написать, например, на React/Redux, пользуясь только функциональными инструментами…

          React — это не ФП
          Redux — да, это ФП. — Но ему противостоит ООП в виде Mobx

          Redux vs Mobx -> ФП vs ООП — можно уже делать ставки кто из них одержит победу! ;-)


          1. staticlab
            17.06.2016 08:49

            В React из ФП есть в виде stateless components. А у Mobx корневое API, включая декораторы, практически всё функциональное.


            1. taujavarob
              17.06.2016 14:05

              staticlab > А у Mobx корневое API, включая декораторы, практически всё функциональное.

              Но при работе с Mobx не надо заботится о том чтобы твои объекты(состояния) были immutables

              Redux vs Mobx -> ФП vs ООП — Mobx одержит победу, имхо ;-)


              1. staticlab
                17.06.2016 14:59

                На первый взгляд их примеры выглядят как приветы от Нокаута и Ангуляра, притом что писать логику инлайном непосредственно в обработчике давно уже дурной тон. Впрочем, я абсолютно согласен, что требование иммутабельности очень сильно затуманивает логику приложения, а react-addons-update и Immutable мало помогают в читабельности. Так что вполне может быть, что Mobx свою нишу найдёт.


            1. TheShock
              24.06.2016 09:15
              +1

              В React из ФП есть в виде stateless components

              stateless components скорее про ооп. Классический view из MVC, где stateless components — View, statefull components — толстый контроллер, а стор и екшены — тонкая модель.


        1. TheShock
          24.06.2016 09:13

          React/Redux, пользуясь только функциональными инструментами

          Как минимум необходимость this.setState полностью разрушает чистоту ;) А вообще на практике при сложной модели такая связка скорее становится процедурной, чем функциональной.


          1. taujavarob
            24.06.2016 18:06

            TheShock > Как минимум необходимость this.setState полностью разрушает чистоту

            3 Reasons why I stopped using React.setState
            https://medium.com/@mweststrate/3-reasons-why-i-stopped-using-react-setstate-ab73fc67a42e#.r4wi5oqu0


  1. VolCh
    16.06.2016 09:18
    +3

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


    1. ApeCoder
      16.06.2016 09:43

      Мне кажется, различие только в том, что в императивном мире есть глобальное общеизвестное состояние в объектно-оритетированном мире у объектов есть identity и state, соответственно, есть понятие изменения как для глобального объекта «мир» так и для любого конкретного объекта (а чтобы объяснить, что состояние неизменно, нужны спецухищрения). Причем состояния объектов являются частью состояния мира.

      В чистом функциональном мире наоборот, эти понятия вводятся дополнительно и локально: если хочешь использовать глобальное состояние надо явно использовать объект RealWord, возможно обернутый в IO monad, можно вводить локальные состояния через State monad, причем они могут не зависеть от состояния мира и быть множественными. За это платят явной передачей этих аргументов везде, где надо.


      1. VolCh
        16.06.2016 10:06
        +1

        Различие даже не в том, что состояние глобально или локально, а в том, что в идеальном императивном мире можно и нужно состояние менять (напрямую или через функции/методы), а в идеальном функциональном нельзя, можно только получить новое состояние из старого. Философски рассуждая, в реальном мире состояния тоже не меняются, а переходят из одного в другое. Но на обывательском уровне мы считаем, что состояние меняем. Не запускаем процесс перевода воды в чайнике из состояния «холодный» в состояние «горячий», а меняем состояние с «холодный» на «горячий». Философски у объектов реального мира состояние — ValueObject, может и обладающий идентичностью, но на практике редко используемой, сравнение идёт по значениям, переход объекта из одного состояния в другое осуществляется присвоением ему нового состояния, а обівательски у объектов реального мира состояние — Entity, переход объекта из одного состояния в другое осуществляется изменением свойств его состояния.


        1. ApeCoder
          16.06.2016 10:21
          +2

          Менять это значит что существует то же самое, но с другим состоянием. Соответственно порождение новой пары (ID, State2) из (ID, State1) семантически эквивалентно «Менять»


          1. VolCh
            16.06.2016 10:47

            Философское и обывательское различие в «менять состояние» состоит в том, делаем ли мы Object.setState(transition(Object.getState()) или Object.getState.transition()


            1. ApeCoder
              16.06.2016 12:00
              +2

              семантически эквивалентно

              allObjects2 = transition(allObjects, objectID)

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


        1. Shamov
          16.06.2016 11:08
          +6

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


          1. ApeCoder
            16.06.2016 11:57
            +1

            «создаем», «уничтожаем» это императивные словечки. Функционально было бы более декларативно типа:

            Вскипевший Чайник ЭТО засвистевший(поставленныйНаПлиту(сНалитойВодой(чайник)))


            1. napa3um
              16.06.2016 12:15
              -1

              результат = дождатьсяСвиста(поставитьНаПлиту(налитьВодуВ(чайник))); // каждая функция возвращает новое состояние

              результат = чайник;
              результат.налитьВоду();
              результат.поставитьНаПлиту();
              результат.дождатьсяСвиста(); // каждый метод меняет состояние

              Первый вариант удобен для конструирования репрезентаций данных в разных формах без влияния логики этих репрезентаций друг на друга, второй вариант удобен для работы с персистентными хранилищами данных; оба варианта одновременно возникают в информационных системах с выделенными архитектурными слоями M и V (или в компонентах/объектах с разделёнными операциями C и Q в терминах CQSR).

              Спор приверженцев ООП с приверженцами ФП о преимуществах своих подходов — это спор о преимуществе двигателя перед коробкой передач.


              1. alsii
                16.06.2016 14:24

                результат = дождатьсяСвиста(поставитьНаПлиту(налитьВодуВ(чайник)));


                эквивалентно:


                результат = чайник;
                результат = налитьВодуВ(результат);
                результат = поставитьНаПлиту(результат);
                результат = дождатьсяСвиста(результат);


                у нас все еще нет изменяющегося состояния?


                Ну хорошо, давайте еще так:


                результат = чайник;
                результат = результат.налитьВодуВ();
                результат = результат.поставитьНаПлиту();
                результат = результат.дождатьсяСвиста();


                1. napa3um
                  16.06.2016 14:29

                  Ваш комментарий похож на возражение по форме, но не очень понятно, в чём суть возражения. В функциональной форме в качестве аргумента каждой последующей применяемой к состоянию функции является копия состояния; в императивной форме операции применяются к одному и тому же экземпляру состояния. Что вам непонятно или кажется некорректным?


                  1. alsii
                    16.06.2016 15:01
                    +1

                    чайник — это состояние? чайник — это экземпляр, пребывающий в состоянии. результат — это некое хранилище, где хранится экземпляр, пребывающий в состоянии.
                    Я к тому, что вот у нас есть ящик результат, в котором стоит чайник, потом некоторый процесс (ну стого говоря исполнитель этого процесса) налить воду достает его из ящика, проверяет его состояние, порождает новый чайник в состоянии "заполненный водой" и кладет его обратно в ящик. Как это выглядит с точки зрения стороннего наблюдателя? Он заглянул в ящик, и увидел там пустой чайник, потом заглянул еще раз, и увидел чайник заполненный водой. С его точки зрения этот тот же самый чайник, потому что для него это "чайник который находится в ящике результат. И он однозначно изменил состояние. Отсюда: присваивание меняет состояние переменной.
                    Насколько я понимаю набор правил в ФП не выполняется, а вычисляется. Пирог же нельзя вычислить. Его можно испечь, выполнив определенные действия. Более того, сам процесс вычисления необходимо выполнять, и в этом процессе будет масса объектов и состояний. Хотя… Возможно существует интерпретатор функционального языка, написанный на функциональном языке?


                    1. napa3um
                      16.06.2016 15:07
                      -2

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


                      1. alsii
                        16.06.2016 15:38
                        +1

                        Спасибо за совет. Я пробовал. Вопросов стало больше. Не смею больше беспокоить.


                      1. Flammar
                        16.06.2016 16:00

                        Про чайник в ФП как фабрику состояний чайника — интересный взгляд, не встречал раньше…


                        1. Sirion
                          17.06.2016 03:03
                          +2

                          После прочтения этой ветки комментариев я уже совсем иначе воспринимаю эту обложку.

                          Заголовок спойлера
                          image


                    1. VolCh
                      16.06.2016 15:24

                      И он однозначно изменил состояние.


                      Не однозначно. Вполне может быть, что он принял новое состояние, а не изменил имеющееся.

                      Насколько я понимаю набор правил в ФП не выполняется, а вычисляется.


                      В общем случае при моделировании реального мира набор правил последовательно (или параллельно) применяется к состоянию объекта, порождая новые состояния и, возможно, производя побочные действия, типа записи в логах :)


                    1. Bronx
                      22.06.2016 07:20
                      +1

                      > Он заглянул в ящик, и увидел там пустой чайник, потом заглянул еще раз, и увидел чайник заполненный водой.

                      Разница начинается в тот момент, когда наблюдатель открывает ящик в середине процесса и суёт палец проверить уровень воды. В императивной парадигме у него есть шанс нащупать полунаполненый чайник, или не нащупать его вовсе, а вместо этого тыкнуть пальцем в глаз другому наблюдателю, наполняющему чайник. Чтобы этого избежать, нужно предусмотреть запирание ящика на время изменения состояния, организовать очередь желающих открыть ящик, избежать ситуаций, когда кто-то открыл ящик A и хочет открыть ящик Б, а кто-то другой — наоборот (дедлок).

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

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


              1. kx13
                16.06.2016 14:25
                +1

                > Спор приверженцев ООП с приверженцами ФП о преимуществах своих подходов — это спор о преимуществе двигателя перед коробкой передач.

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

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

                Вот поэтому и надо изучать разные парадигмы, чтобы понимать, что и где удобнее.


                1. napa3um
                  16.06.2016 15:02
                  -1

                  Вы опять противопоставили ФП и ООП в стиле противопоставления дизельного или бензинового двигаетля в выборе оборудования для автомобиля. Я же как раз и утверждаю, что ФП не заменяет ООП, а живёт с ним рядом, беря на себя другие функции в составе всего автомобиля (проекта).


              1. Flammar
                16.06.2016 14:55

                Для каждого промежуточного результата сделать отдельный тип. Для каждой операции сделать метод в каком-нибудь классе. И заавтовайрить через dependency injection. Пусть контейнер императивные цепочки строит.


              1. FForth
                16.06.2016 21:04

                : ДождатьсяСвиста Чайник НалитьВоду ПоставитьНаПлиту;

                P.S. Состояния вызываются последовательно (контекст — Чайник тоже может передаваться между словами)


                1. ApeCoder
                  17.06.2016 11:36

                  Только если како-то слово запихает на стек больше ем должно, или возьмет больше надо запихивать в стек в свой мозг и им париться


            1. Shamov
              16.06.2016 12:23
              +1

              С этим ничего не поделаешь. Человек мыслит «на языке». И хотя некоторые с этим не согласны, в науке это мейнстримно признанная гипотеза. Она называется гипотеза Сепира-Уорфа.


              1. Bas1l
                16.06.2016 12:31

                А почему тогда все еще называется гипотезой?


                1. napa3um
                  16.06.2016 12:43

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


                1. Shamov
                  16.06.2016 12:46
                  +1

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


              1. ApeCoder
                16.06.2016 12:36

                Поинт не в том, на языке или не на языке, а в том, что сама по себе семантика императивная. Мы не создаем ничего и не уничтожаем, мы просто описываем что нам надо. Что нам не надо получается оттуда само и уничтожается или создается при трансляции на нижележащие императивные уровни


                1. Shamov
                  16.06.2016 12:53

                  Семантика — это свойство языка. У императивных языков императивная семантика. В них есть такие категории как «создать», «уничтожить». У функциональных же языков семантика не императивная. Им такие категории чужды. Вместо этого у них есть другие, которые позволяют лаконично описывать результат (конечный или промежуточный), но плохо подходят для прямого описания последовательных шагов.


                  1. ApeCoder
                    16.06.2016 13:18
                    +1

                    У IO monad императивная семантика или функциональная? Я имею ввиду, что императивный язык можно рассматривать как приложение функционального языка


                    1. Shamov
                      16.06.2016 14:05

                      IO-монада — это костыль, предназначенный для скрещивания функциональной семантики с императивной. Соответственно, и семантика у неё костыльная… т… е. смешанная. Императивный язык можно рассматривать как приложение функционального только при наличии соответствующих костылей. Без соединяющих костылей императивные языки практически бесполезны в мире чистых абстракций, а функциональные — в реальном мире. Между прочим, существует костыль и для соединения в обратном направлении — библиотека шаблонов STL. Она позволяет выражать логику программы почти на чистых абстракциях в сугубо императивном языке.


                      1. napa3um
                        16.06.2016 14:08
                        +1

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


                        1. Shamov
                          16.06.2016 14:29
                          +2

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


                          1. napa3um
                            16.06.2016 14:35
                            -1

                            Я не пытаюсь подкрутить определение, я пытаюсь подкрутить мотивы собеседника в использовании инструмента ФП в «реальных проектах» (и снизить риск разочарований от его неоправданного использования). Если чертёжнику дать циркуль, он не будет переживать по поводу того, что циркулем нельзя вычертить весь чертёж, но останется доволен тем, что окружности теперь получаются ровные.


                            1. Shamov
                              16.06.2016 15:14
                              +1

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


                          1. 0xd34df00d
                            17.06.2016 04:41
                            +1

                            Давайте лучше начнём с семантики монады ST? Какая у неё семантика?

                            Как это связано с тем, что ST — escapable, а IO — нет? Как это всё связано с rank-2 polymorphism?


                      1. ApeCoder
                        16.06.2016 15:41
                        +2

                        Это настолько же костыль, насколько библиотека windows forms костыль для C# для работы с окнами. Это просто способ выразить императивную семантику через функциональную. В clean для этого используют объект World


                        1. Shamov
                          16.06.2016 15:59
                          +2

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


                          1. VoidEx
                            16.06.2016 16:20
                            +3

                            Любая библиотека — костыль? Или только та, без которой удобно не поработать? А если можно удобно и без библиотеки, зачем она вообще нужна?
                            Костылями зовут кривые решения, затыкающие какую-то проблему, но не устраняющие причин и не обладающие достаточной общностью.


                            1. Shamov
                              16.06.2016 16:38

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


                              1. VoidEx
                                16.06.2016 16:42
                                +2

                                В этом смысле if-else — костыль у энергичных языков?


                              1. ApeCoder
                                16.06.2016 16:44

                                То есть чем больше язык позволяет выразить при помощи библиотек тем он костыльнее. Наверное самый костыльный это ЛИСП


                              1. napa3um
                                16.06.2016 16:56

                                Парадигма автомобиля заключается в перемещении полезного груза по поверхности. Нужно выкинуть из автомобиля все детали кроме колёс как костыли?


                                1. Shamov
                                  16.06.2016 17:27

                                  Костыли не нужно выкидывать. Зачем? Без них ничего работать не будет. Нужно просто избегать стокгольмского синдрома. Т.е. избегать мыслей в стиле, что эти прекрасные костыли, отлично выполняющие свою задачу, — это новые ноги. Костыли нужны, чтобы помогать неработающим ногам ходить, как бы, на ногах. Но они не нужны тем, кто отказался от идеи прямохождения и пересел в коляску. Коляска — это другой тип костылей, но сейчас речь не об этом. Главное, что в парадигме прямохождения всё, кроме собственно ног, является костылями.


                                  1. napa3um
                                    16.06.2016 17:37

                                    Слово «костыль» в вашем лексиконе кажется избыточным и бессмысленным, инженеры с программистами в вашем лексиконе легко превращаются в костыльмэйкеров.


                                    1. Shamov
                                      16.06.2016 17:46
                                      +1

                                      А вы посмотрите на этих программистов… По-моему, очень точное слово.


                  1. Source
                    16.06.2016 13:49

                    плохо подходят для прямого описания последовательных шагов.
                    Почему же, для описания последовательных шагов в виде цепочки функций ФП отлично подходит. Но хуже подходит для описания нескольких взаимовлияющих на разделяемое состояние последовательностей. Впрочем, до абсурда можно что угодно довести… давайте печь пирог при помощи ООП и классов Духовка, Противень, Миска, Мука, Сода, Соль, Масло, Сахар, Яйцо, Кефир, Банан, Орех, Полотенце.
                    Автор тупо хитрит, когда приводит рецепт из кулинарной книги в качестве императивной программы. Рецепт — это далеко ещё не программа.


                    1. Flammar
                      16.06.2016 13:59
                      +1

                      давайте печь пирог при помощи ООП и классов Духовка, Противень, Миска, Мука, Сода, Соль, Масло, Сахар, Яйцо, Кефир, Банан, Орех, Полотенце.
                      Ниже приводили пример, когда духовок, противней, мисок и всего остального имеется в наличии по много экземпляров. Тогда такой прикол с классами, состояниями и событиями будет вполне уместен.


                      1. Source
                        16.06.2016 17:56
                        +1

                        Это для конкурентного то выпекания? Ну да мьютекс на миску — это так похоже на реальный мир, не то, что сообщение от одного пекаря другому, что миска освободилась :-D


                        1. Azoh
                          17.06.2016 13:06
                          +2

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


                    1. Shamov
                      16.06.2016 14:10

                      Слово «последовательные» применительно к шагам алгоритма обозначает строго прямую последовательность… не обратную.


                      1. VolCh
                        16.06.2016 15:27

                        Не путайте последовательность выполнения и последовательность записи.


                        1. Shamov
                          16.06.2016 15:52

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


                          1. ApeCoder
                            16.06.2016 15:57
                            +2

                            Эта последовательность записи просто для того, чтобы было понятнее неФП людям. ФП люди используют pipe оператор или еще что:

                            тесто |> месить |> поставитьВДуховку |> влючить

                            оператор |> берет левую часть и применяет к ней функцию, указанную в правой


                            1. Shamov
                              16.06.2016 16:11

                              В итоге мы пришли к тому, что функциональные языки больше подходят для описания функциональных алгоритмов. Замечательно! Но только как-то по-капитански…


                              1. ApeCoder
                                16.06.2016 17:19
                                +2

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


                      1. Source
                        16.06.2016 17:48
                        +2

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

                        Вот, например, выпекание пирога на Elixir:
                        http://pastie.org/10879491

                        Запускается 4 актора (печь, противень и 2 миски) и всё прекрасно записывается при помощи отправки им сообщений.
                        Да, эта задача вертится вокруг состояний, но не надо думать, что функциональные языки не могут работать с состояниями. Просто они не используют для этого классы.


              1. k12th
                16.06.2016 13:09

                Признана она в лучшем случае в своем слабом варианте.


                1. napa3um
                  16.06.2016 13:20
                  -3

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


                  1. k12th
                    16.06.2016 13:42
                    +2

                    Где-то можно об этом прочитать подробнее?


                    1. napa3um
                      16.06.2016 13:43
                      -6

                      Можно.


                1. Shamov
                  16.06.2016 13:41

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


              1. Flammar
                16.06.2016 13:10

                Первый раз встречаю такую сжатую формулировку этой гипотезы…


                1. Shamov
                  16.06.2016 13:36
                  +2

                  Краткость — с.т. :)


              1. Idot
                17.06.2016 11:50

                А как быть с теми кто размышляя размахивает руками рисуя образы?

                PS а вообще, математики делятся на Алгебраистов и Геометров, которые привыкли размышлять по-разному.


                1. Shamov
                  17.06.2016 12:40
                  +1

                  Язык жестов — это тоже язык. Образами люди мыслят только во сне. Именно поэтому там всё так мутно и иррационально. Если тебе во сне кажется, что ты видишь издалека, например, своего друга Пашу, и ты подходишь, чтобы рассмотреть поближе, то всегда оказывается, что ты угадал… это и правда Паша. Проблема в том, что на языке образов (без заранее оговоренного языка) нельзя выразить даже банальное отрицание. Во сне в мозгу не может возникнуть мысль «это не Паша». Любой, кто мог бы быть Пашей, всегда неизменно оказывается Пашей.


          1. napa3um
            16.06.2016 12:52

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


            1. Shamov
              16.06.2016 13:01
              -2

              Фразочки вроде «субъективная репрезентация объективной реальности» давно пора забыть. Они звучали свежо во времена Декарта. В наши же дни философия ушла далеко вперёд. И уже минимум сто лет не считается, что объективная реальность на самом деле существует. Новая парадигма состоит в том, что существует только субъективная реальность, иногда кажущаяся объективной тем, кто недостаточно проницателен.


              1. napa3um
                16.06.2016 13:07
                +3

                Вы озвучили точку зрения так называемого наивного идеалиста или солипсиста, которая как раз и была актуальна во времена Декарта. А в современном научном (нео/пост)позитивизме существование объективной реальности постулируется как данность, а не как что-то, что нужно обосновывать (хотя вот свойства этой объективной реальности в своём пределе могут быть и непознаваемыми, позитивисту будет достаточно работающей формулы какой-либо физической закономерности и без её философской интерпретации).


                1. Shamov
                  16.06.2016 13:56

                  Отнюдь. Когда я говорил про сто лет, я имел в виду то, что граница проходит где-то по середине Витгенштейна. Точка перехода — это момент, когда ранний Витгенштейн осознал ошибочность позитивизма, отринул его и превратился в позднего Витгенштейна. Ну, а нео-/постпозитивизм — это очевидная чушь. Особенно ясно это становится после того, как вы обозначили главный момент: существование объективной реальности постулируется как данность. Какой же это вообще позитивизм? Используя такие откровенно читерские приёмчики, можно прийти к абсолютно любым выводам. Схема рассуждений довольно примитивная. Не можем что-то обосновать, но нам очень нужно, чтобы это было так? Не вопрос! Просто постулируем это как данность. А тот вариант, что мы не можем это обосновать именно потому, что это не так, в расчёт не берём.


                  1. napa3um
                    16.06.2016 14:02
                    +2

                    Ваши аргументы поверхностны и наивны, отсылки к Витгенштейну некорректны, а мотивы их озвучивания неясны. Вы пытаетесь меня убедить, что объективная реальность перестала быть предметом научного метода? Не думаю, что у вас получится (проблемы возникнут прежде всего методологические, а не ввиду моего сопротивления вашим интерпретациям). Пытаясь доказать мне «истинное положение вещей в теме интерпретации субъективных переживаний» вы автоматически указываете пальцем на объективную реальность.


                    1. alsii
                      16.06.2016 14:34
                      +2

                      @napa3um Shamov спасибо! Вы сделали мой день. Я всегда подозревал, но сейчас реально увидел, как занимаются философией:


                      Философ А: нео-/постпозитивизм — это очевидная чушь… Схема рассуждений довольно примитивная… Откровенно читерские приёмчики


                      Философ Б: Ваши аргументы поверхностны и наивны… Отсылки… некорректны… Мотивы их озвучивания неясны


                      1. napa3um
                        16.06.2016 14:40

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


                        1. Shamov
                          16.06.2016 14:50
                          +1

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


                          1. napa3um
                            16.06.2016 14:57

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


                            1. Shamov
                              16.06.2016 15:22
                              +1

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


                              1. napa3um
                                16.06.2016 15:39

                                Вы забыли, как написали:
                                > Не понимая содержания разговора, он видит только его форму и думает, что форма — это всё, что есть.
                                Теперь попробуйте перечитать мой ответ.


                          1. alsii
                            16.06.2016 15:23
                            +3

                            Вообще говоря, для меня так и осталось загадкой что же такое изучают философы. Курс философии в техническом вузе убедил меня в том, что предмет философии — это изучение мнений абсолютно разных людей по слабосвязному кругу вопросов. Чтобы сдать экзамен требовалось выучить кто и что говорил/писал по определенному вопросу. При этом каких либо доказательств истинности этих мыслей ни в учебнике, ни на лекции не приводилось. Просто факт: А говорил, что Б — это В. Г не соглашался с ним и говорил, что Б — это Д. Е высмеивал их обоих, и говорил, что нам никогда не узнать что такое Б на самом деле, но при этом был точно уверен, что Б это не Ж. Курс назывался "Марксистско-ленинская философия", поэтому в середине главы утверждалось: "Б — это З, потому что так говорили И, Й и, самое главное К. И когда все народы осознают, это, то все заживут дружно и счастливо". Дальше обычно было написано, как замечательно что Б — это З, какие молодцы И, Й, и особенно К. Как мы счастливы, что понимаем это, и как несчастны все остальные. Но этого в билетах уже не было и можно было не читать.


                            1. Shamov
                              16.06.2016 15:38

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


                              1. alsii
                                16.06.2016 15:53
                                +1

                                Если же исходить из обратного, то получится геометрия Лобачевского.


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


                                1. Shamov
                                  16.06.2016 16:04

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


                              1. Unrul
                                17.06.2016 01:07

                                Хорошее сравнение. Только это называется моральным релятивизмом и предполагает, что люди не являются сознательными существами способными к познанию окружающего мира. Что, судя по всему, слегка не верно. Хотя, если предположить отсутствие объективной реальности, то всё ok.


                                1. Shamov
                                  17.06.2016 06:39

                                  Предположить можно было бы наличие объективной реальности. А её отсутствие, как бы, само собой подразумевается в ситуации, когда наличие не доказано. Но в любом случае это всё не важно. Быть сознательным существом и познавать окружающий мир можно вне зависимости от того, насколько этот мир объективен.


                                  1. napa3um
                                    17.06.2016 06:58

                                    «Давайте называть объективное субъективным, но это не важно, я всё равно не понимаю этих терминов.»


                                    1. Shamov
                                      17.06.2016 07:16

                                      Можно делать и наоборот: называть субъективное объективным, думая, что это имеет хоть какое-то значение.


                            1. napa3um
                              16.06.2016 15:44

                              Технари-редукционисты пытаются свести философию к набору атомарных правил вывода или к каким-то фундаментальным законам (мыслят в механистической парадигме ньютоновской физики), и терпят поражение ввиду того, что сама попытка такого наивного сведения — уже предмет философии. Философия — это о том, как и почему люди думают обо всём, о поисках критериев эволюции мысли, а не о каких-то конкретных таких критериях, выбранных в качестве догматов (аксиом, постулатов). А вот выбранные конкретные аксиомы и постулаты порождают различные науки, «прикладные» результаты философии.


                              1. alsii
                                16.06.2016 16:02
                                +2

                                Это хорошо. Ну и как и почему люди думают? Какие критерии эволюции мысли удалось найти? Под "атомарными правилами вывода" вероятно имеется в виду логика? Философия не нуждается в логике?


                                1. napa3um
                                  16.06.2016 16:07
                                  -1

                                  Попробуйте порассуждать об этом сами или почитайте соответствующую литературу. Меня подобное обсуждение с вами вряд ли заинтересует.


                                1. Unrul
                                  17.06.2016 01:40

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


                                  1. taujavarob
                                    17.06.2016 14:09

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

                                    Почему не получилось? — Был такой теолог — Райму?нд Лу?ллий — он одной логикой(!) обращал мусульман и иудеев в католицизм в 12 веке (атеистов тогда не было, были ещё местами язычники). — Так он интересную механическую машину выводов то изобрёл! ;-)


                    1. Shamov
                      16.06.2016 14:41

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


                      1. napa3um
                        16.06.2016 14:47

                        Похоже, вы, как и многие, путаете понятия «объективность» (независимость от субъекта) и «истинность» (непротиворечивость и однозначность в некой выбранной формальной системе). Ваши «очевидности» и «убедительности» к объективности не имеют никакого отношения.


                        1. Shamov
                          16.06.2016 15:09

                          Ну, всё дело в том, что я не настоящий философ. Я просто выучил кое-какие умные слова.


                    1. Azoh
                      16.06.2016 14:49

                      >объективная реальность перестала быть предметом научного метода
                      Для начала она никогда не была. Научный метод — совокупность инструментов изучения. Можно было бы предположить, что «объективная реальность» — это «предмет» изучения науки. Только с соответствии с «научным методом» предметом изучения науки является «реальность наблюдаемая». А это, как говорят, две большие разницы.


                      1. napa3um
                        16.06.2016 14:52

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


                        1. Azoh
                          16.06.2016 15:30

                          >


                        1. Azoh
                          16.06.2016 16:34

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


                          1. napa3um
                            16.06.2016 16:38

                            Для применения научного метода придётся считать предмет применения объективным, иначе получится бессмысленная операция с бессмысленным результатом. Вне зависимости от вашего непонимания научного метода и сути объективной реальности.


                            1. Azoh
                              16.06.2016 19:37

                              Ладно, вопросы существования «объективной реальности» я считаю вопросами того же порядка, как и вопросы существования богов, так что не могу сказать, что глубоко всем разумом понимаю проблематику объективности реальностей. Однако же интересно мне, что именно в научном методе требует что-то от предмета изучения. Это же, по сути, набор правил того, как правильно из набора фактов делать модели (по сути вводить постулаты), а так же того, как правильно ставить эксперименты для получения новых фактов


                              1. napa3um
                                17.06.2016 07:38

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


                      1. alsii
                        16.06.2016 15:27
                        +1

                        Меня это всегда забавляло. Если реальность существует лишь как представление о ней некоего разума, объективен ли сам этот разум? Если да — то он уже является объективнйо реальностью. Если нет, то мы впадаем в бесконечную рекурсию.


                        1. Shamov
                          16.06.2016 15:45

                          Декарт эту рекурсию прервал своим «Я мыслю — значит существую!» У любого сторонника картезианской философии теперь нет никаких проблем с этим.


                          1. alsii
                            16.06.2016 15:58

                            А как с этим справляются остальные? Следует ли из этого рассуждения несостоятельность не признающих этого учений?


                            1. Shamov
                              16.06.2016 16:17

                              Да начхать на остальных. Современная западная цивилизация построена на картезианском учении. Так что у любого, кто с ним солидарен, всё будет хорошо. А на остальных наплевать. Они имеют право на своё особое мнение. Но говорить с ними особо не о чем.


                              1. alsii
                                16.06.2016 16:41
                                +2

                                Ага. Уже третий раз встречаю сегодня этот ход: "Не согласен? Не понимаешь? Продолжаешь задавать вопросы? Говорить с тобой нре о чем!". Все-таки философия сильно отличается от естественных наук. И даже от неестественных :)


                                1. napa3um
                                  16.06.2016 16:45

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


                                  1. alsii
                                    16.06.2016 17:37
                                    +1

                                    Да я не настаиваю на пруфах. Готов поверить вам на слово :-) Вот в данном конкретном случае. Спрашиваю, как решают этот вопрос другие направления философии? А мне в ответ: да гачхать на них. Я это понял так: "Нечего их вообще слушать, они ничего не понимают". Получается примерно так. Я сейчас сформулирую для себя некий набор утверждений: "Красное — это синее", "мягкое — это твердое", "зеленое не бывает угловатым". Все. Я философ. На всех, кто думает иначе: нчхать. Второе утверждение противоречиво? "Мы, философа не нуждаемся в логике. Логика сама предмет нашего изучения. Мы можем выдумать сто разных логик с парадоксом и кванторами". Если какие-то невежды спрашивают, что получится если взять угловатое и покрасить в зеленый цвет, то мы их посылаем читать книжки, ибо нечего тратить наше драгоценное время. Вообще весело, но какой от такого подхода практический результат? Ну и на религию еще смахивает...


                                    1. napa3um
                                      16.06.2016 17:52

                                      Какая вам разница, на что это смахивает и на то, можно ли называть бессмысленный набор тезисов философией? Как сформулируете практические критерии такой разницы, так и научитесь формулировать правильные («философские») вопросы, ответы на которые заставляют принимать то или иное допущение о свойствах реальности. И да, религиозные догматы от научных постулатов отличаются не по каким-то формально-логическим критериям, а исключительно по своему приложению. Догма, аксиома, постулат, допущение — это синонимы, обозначающие базовые предпосылки для последовательности умозаключений в рамках любой дисциплины, даже богословской.


                                      1. alsii
                                        16.06.2016 18:12
                                        +2

                                        Научные постулаты отличаются от религиозных догматов тем, что они фальсифицируемы. Кстати, являются ли фальсифицируемыми принципы, положенные в основу философии? В философии вообще существует понятие "доказательство"? Мне всегда казалось, что нет.


                                        1. napa3um
                                          16.06.2016 18:47

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


                                1. Shamov
                                  16.06.2016 16:56

                                  Основное отличие состоит в том, что философия пытается ответить на другие вопросы. По большому счёту, существует лишь три главный вопроса: «что сделать?», «зачем это делать?» и «как это сделать?» Все реальные проблемы в конечном итоге сводятся к ним. Естественные науки пытаются ответить лишь на вопрос «как что-то сделать?» Философия же берёт на себя два других вопроса. Она, во-первых, формулирует саму проблему, которую нужно решить. Часто бывает так, что проблема вовсе не очевидна. Во-вторых, она может сформулировать мотивационную часть, ответив на вопрос «зачем?». Причём сформулировать достаточно убедительно для того, чтобы нашлись реальные люди, готовые тратить на решение проблемы свое время и силы.


                                  1. alsii
                                    16.06.2016 18:20
                                    +1

                                    Формулировка проблемы, это первая часть любой студенческой работы, не говоря о более. Так что тут у философии нет монополии. Вопрос "зачем" так же всегда решается. Например это может быть "технико-экономическое обоснование" или еще что-то. Да что там наука. Каждый из нас решает эти вопросы по 100 раз на дню: "Что то мне скучно… Не пойти ли мне в кино? или может лучше пива выпить...". То же у И. Маска: "Что-то мне скучно. Не создать ли мне платежную систему? Ну вот, теперь денег дофига… Не полететь ли мне на Марс? Или лучше сделать электрическую машинку? А пофиг… Пусть будет и то и другое". Теперь я вижу разницу. Маск — философ, а я, увы, нет :(


                                    1. Shamov
                                      16.06.2016 18:59

                                      Маск, безусловно, философ. В этом можете даже не сомневаться. Ещё у Платона была идея о том, что миром должны править философы. Именно это и случилось. Никто просто не заметил. Поскольку философы сейчас выглядят не так, как в Древней Греции. Они сейчас ходят в костюмах и работают советниками президентов, консультантами владельцев крупного бизнеса, а иногда и сами мутят какой-то бизнес. В общем, выполняют ту самую работу, которую можно назвать «управление миром».


                                      1. alsii
                                        16.06.2016 19:03

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


                                        1. Shamov
                                          16.06.2016 19:10

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


                                1. Unrul
                                  17.06.2016 01:52
                                  +1

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


                          1. napa3um
                            16.06.2016 16:01

                            «Cogito, ergo sum» — это о пределе убеждения в собственной рациональности («непогрешимости умозаключений»), а не о существовании объективной реальности. Любой выдуманный литературный персонаж по Декарту существует уже только потому, что может себе в этом признаться, например.


                            1. alsii
                              16.06.2016 16:07
                              +1

                              Тогда это не разрыв рекурсии. Это просто переопределение термина "существую". Т.е. вопрос остается.


                              1. napa3um
                                16.06.2016 16:12

                                Всё верно. Вопрос о существовании объективной реальности пока остался без однозначного ответа, польза принятия её существования является «самоочевидной» и не требует обоснования (т.к. альтернативные взгляды получаются всегда менее мощные в предсказательной силе). Объективная реальность существует потому, что существует, но если хочешь — попробуй отказаться от неё. Не смог? Тогда ешь что дают.


                            1. Shamov
                              16.06.2016 16:26

                              Внутри реальности, создаваемой воображением читателя, выдуманный литературный персонаж, безусловно, существует. Он не существует в нашей с вами реальности. Но в ней он и мыслить может. Так что всё чётко.


                              1. napa3um
                                16.06.2016 16:28

                                Но без чёткого разделения субъективной (создаваемой воображением читателя) и объективной (существующей вне зависимости от существования читателей) реальности. Так что не всё чётко.


                                1. Shamov
                                  16.06.2016 16:46

                                  Ну, проблема разделения и его чёткости — это субъективная проблема. Будем исходить из ваших предпосылок о том, что объективная реальность существует. Представим себе два камня, которые лежат на земле. Вы не поверите! Им абсолютно начхать на то, различаются ли они чем-то между собой. Они об этом не думают. Потому что вообще не думают. Так же и с реальностями. Различие между субъективной реальностью литературного произведения и тем, что вы называете объективной реальностью, актуально только для читателя, который думает об этом.

                                  С практической точки зрения удобно пользоваться категорией «различимое различие» (difference that make a difference). Когда субъект видит разницу между А и B, которую может как-то описать на своём языке, считается, что разница есть. Если же субъект разницы не видит или не может её описать, то значит и разницы никакой нет. Например, две картофелины примерно одинакового размера имеют разную форму. Это очевидно. Тем не менее, тому, кто будет есть картофельное пюре, это различие безразлично. Для него различия, как бы, и нет.


                                  1. napa3um
                                    16.06.2016 16:51

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


                                    1. Shamov
                                      16.06.2016 17:05

                                      Это не софизм, а суровая правда жизни. Конструктивный вывод состоит в том, что бороться с этим состоянием дел не нужно. Люди могут сотрудничать друг с другом не только тогда, когда у них одна общая правда. Достаточно сойтись в каких-то отдельных моментах, важных для каждого из них. Те же различия в описаниях реальности, которые не имеют для них значения, можно считать несуществующими. В результате объективной реальности нет, а взаимовыгодное сотрудничество есть.


                                      1. napa3um
                                        16.06.2016 17:11

                                        Не уверен, что ваши личные конфликты и проблемы с работой в команде имеют какое-то отношение к проблематике обоснования существования объективной реальности. Хотя подобное и довольно распространено — так называемая интеллектуализация своих личных переживаний путём формулирования их в наукообразной обобщающей (далеко не всегда корректно обобщающей, но дистанцирующей) терминологии.


                              1. alsii
                                16.06.2016 16:52
                                +1

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


                                1. Shamov
                                  16.06.2016 17:16

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


                                  1. napa3um
                                    16.06.2016 17:18

                                    Перестаньте, вы явно не в теме. Вы наличием множества субъективных реальностей пытаетесь обосновать отсутствие объективной, что, конечно же, просто смешно.


                                    1. Shamov
                                      16.06.2016 17:40

                                      Все позитивисты мира сейчас виртуально смеются на вашей фразой «обосновать отсутствие». Любому позитивисту с детства известно, что отсутствие обосновать невозможно, и потому обосновывать всегда следует только наличие. И до тех пор, пока вам не удастся обосновать наличие объективной реальности, у меня даже никакой проблемы с этим нет. Поскольку всё, что вы говорите, — это ни о чём. (Простой постулат о наличии я обоснованием не считаю.)


                                      1. napa3um
                                        16.06.2016 17:58

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


                                        1. Shamov
                                          16.06.2016 18:18

                                          Могу даже одним тезисом сформулировать. Простое постулирование существования столь спорной вещи как объективная реальность — это читерский приём. В рамках философских рассуждений такой приём вполне годится. Но гордиться тут особо нечем.


                                          1. napa3um
                                            16.06.2016 18:53

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

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


                                            1. Shamov
                                              16.06.2016 19:05

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


                                              1. napa3um
                                                16.06.2016 19:26

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


                                                1. Shamov
                                                  16.06.2016 21:03

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


                                                  1. napa3um
                                                    16.06.2016 21:08

                                                    По-вашему, ваш солипсизм свежее и актуальнее. Ваше резонёрство очевидно.


                                                    1. Shamov
                                                      16.06.2016 21:21

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


                                                      1. napa3um
                                                        16.06.2016 21:25

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


                                                        1. Shamov
                                                          16.06.2016 21:29

                                                          По-вашему, я не знаю, что такое солипсизм? Интересный заход…


                                  1. alsii
                                    16.06.2016 18:02
                                    +1

                                    погодите, описание подразумевает существование некоего субъекта, который описывает. Тогда выходит, что объективно ничто не существует. Далее, как быть с существованием того, о чем ни одному субъекту неизвестно. Соответственно нет и описаний. Оно существует? Дальше. Если есть описание, можно ли утверждать, что существует и сам объект? Например существует ли "Чайник Рассела"? Или невидимый розовый единорог?


                                    1. Shamov
                                      16.06.2016 18:47

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

                                      Существование того, о чём никто не знает, находится под вопросом. Нельзя сказать ни да, ни нет. Многие вещи существуют как чистый вымысел. Некоторые существуют как мифы. Кто-то верит в их существование, а кто-то не верит. Но обязательно нужен кто-то, кто хоть что-то об этом знает. Чайник Рассела существует, как минимум, в качестве мема. Невидимый розовый единорог тоже в некотором смысле существует. Хотя бы как пример невозможного. Вообще абстрактные категории могут существовать без всяких ограничений. Параллельное существование реальных прототипов необязательно. Есть один очень мощный инструмент абстрагирования — отрицание. Например, существуют сигареты. Все понимают, что это такое. А теперь попробуйте себе представить реальный прототип абстракции под названием «не сигарета». Не какую-то конкретную вещь, которая бы не была сигаретой, а именно «не сигарету» вообще. Это что такое? Как это выглядит? Оно видимо или невидимо? Ответов на эти вопросы нет. Потому что это чистая абстракция. Так же и невидимый розовый единорог. Это абстракция. Пример невозможного в реальном мире. Именно в этом качестве оно и существует. Только в сознании людей.


                                      1. napa3um
                                        16.06.2016 19:43

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


                                        1. Shamov
                                          16.06.2016 21:15

                                          Разумеется. Я же просто любитель.


          1. VolCh
            16.06.2016 15:15

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


            1. Shamov
              16.06.2016 15:29

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


              1. VoidEx
                16.06.2016 15:50

                Так «один и тот же объект» — тоже условность.


                1. Shamov
                  16.06.2016 16:31

                  Я даже больше скажу. Вообще всё — условность. Даже сама условность — это тоже условность. Вопрос лишь в том, на каком уровне условности выбрать точку опоры, чтобы можно было от неё оттолкнуться и сделать что-то продуктивное. Хотя продуктивность — это, конечно, тоже условность.


                  1. napa3um
                    16.06.2016 16:33

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


                1. alsii
                  16.06.2016 16:36
                  +1

                  Эту фишку в юриспруденции любят: "Ваша честь! Стоящий перед Вами человек, вовсе не тот, который совершил это ужасное преступление! Тот негодяй, умер там, вместе со свойе жертвой! Подвергнуть же наказанию этого невинного агнца, с совершенно иным отношением к жизни и к людям, означало бы совершить преступление еще более бесчеловечное". ;-)


                  1. VoidEx
                    16.06.2016 16:44
                    +1

                    А он и есть другой, однако свойства нового агнца сходны с исходным, а мы хотим породить нового агнца, с отличными свойствами, для чего вынуждены предпринять некие действия :)


          1. VoidEx
            16.06.2016 15:49

            Если вода выкипает, а я периодически доливаю холодной — у меня там одна единственная вода в состояниях «выкипает» и «нагревается, температура t», или разные воды?


  1. ApeCoder
    16.06.2016 09:57
    +11

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

    На Haskell то, что он написал, выглядело бы примерно так:

    parseVarant = parseA  <|> parseB <|> parseC <|> parseD 
    



    1. GrizliK1988
      16.06.2016 10:12
      +1

      Любопытства ради: а если парсеров неопределенное количество?


      1. VoidEx
        16.06.2016 10:18
        +4

        Неопределённое в каком смысле? Если список парсеров, или если вы к готовому хотите ещё добавить вариант?

        someParser = foldr1 (<|>) [parseA, parseB, parseC, parseD]
        someParser' =  someParser <|> parseX
        

        соответственно


    1. Bas1l
      16.06.2016 11:55
      +2

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


      1. Source
        16.06.2016 13:53
        -3

        Попробуйте написать реальную программу, которая печёт пирог. Рецепт — это ближе к ТЗ, чем к программе. И компьютер так не работает.


        1. Source
          16.06.2016 23:56

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


      1. kmikeru
        16.06.2016 14:10

        Но есть же и другой пример, «Паблик статик файнал Борщ борщ нью Борщ», разве это ближе к задачам и реальному миру?


    1. 0xd34df00d
      17.06.2016 04:56
      +1

      Автор на нефункциональном языке не с той стороны зашёл.

      Сначала берётся boost.optional, потом пишется тайпкласс MonadPlus со всей своей иерархией, потом msum. И всё.


  1. Zealint
    16.06.2016 10:22
    +1

    Есть ещё одна причина непопулярности функциональных языков, по крайней мере, в сфере сложных научных расчётов. На функциональном языке нельзя написать ни одной эффективной (и одновременно полезной) программы, которая выжимала бы из процессора максимум. Это можно легко сделать на Си, на Паскале (и Delphi) в связке с ассемблером… на Java и C#, к сожалению, нельзя, ещё можно на Фортране. Да, можете со мной спорить, если есть опыт и аргументы, но факт таков: ни одна из сложных задач, по крайней мере, из моего списка задач, не будет решена на функциональном языке. Они все будут решены на простых императивных языках с помощью кластеров и видеокарт.

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


    1. Oxoron
      16.06.2016 10:31
      -2

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


    1. youlose
      16.06.2016 11:17
      -2

      «Они все будут решены на простых императивных языках с помощью кластеров и видеокарт. „
      Как раз в этой-то области и цветёт функциональное программирование как парадигма. Ибо чтобы распараллелить задачу надо произвости декомпозицию до простых частей, а это и есть суть функционального подхода.
      Да и чисто императивных языков сейчас всё меньше и меньше (а может быть и вообще не осталось), сплошь и рядом пытаются расширять их для написания в функциональной парадигме.


      1. Bas1l
        16.06.2016 11:48
        +7

        На суперкомпьютерах обычно поддерживаются только три компилятора: С, С++ и Fortran. Параллельность—за счет Message Passing Interface плюс OpenMP. Так что там, по крайней мере, функциональное программирование точно не цветет.


        1. youlose
          16.06.2016 13:21
          -2

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


    1. Idot
      16.06.2016 11:23
      -5

      на Паскале (и Delphi) в связке с ассемблером…

      Так на любом в связке с ассемблером можно! lol
      C#, к сожалению, нельзя

      Читал рекомендации по настройке C# с отключением кучи всего и получением результата по скорости близкого к C++ Net.
      На функциональном языке нельзя написать ни одной эффективной (и одновременно полезной) программы, которая выжимала бы из процессора максимум. Это можно легко сделать на Си

      Сам не проверял, но читал про следующий трюк:
      — берём функциональный код f(a,b)
      — а затем преобразуем получая вот такое a b f
      => получился Forth! Который, по скорости вполне сравним с C => PROFIT!


      1. Bas1l
        16.06.2016 11:46
        +3

        Так надо же с C++ сравнивать, а не с C++ .Net. Конечно, с другим—таким же медленным— .Net языком сравнение будет хорошим. Там была, скорее всего, та же самая garbage collection, в первую очередь.


      1. Idot
        16.06.2016 12:46

        на Паскале (и Delphi) в связке с ассемблером…

        Так на любом в связке с ассемблером можно! lol

        -1

        Если есть что возразить — возражайте!

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


    1. eoffsock
      16.06.2016 14:20

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


    1. staticlab
      16.06.2016 14:20
      -1

      А шейдерная программа не есть чистая функция, которая применяется (map) ко множеству фрагментов?



    1. Akon32
      16.06.2016 14:20

      А какие у вас задачи?

      У меня вполне получалось писать т.н. «научные расчёты» на Scala, и если иммутабельностью не упарываться (т.е. тыкать всюду массивчики и мутабельные хэш-таблицы) и память очень часто не выделять, работает всё сносно. OpenCL вполне подключается, и кластеры наверно тоже можно задействовать (мне не приходилось).

      Delphi, насколько я помню, выдавал не слишком уж оптимальный код (до внедрения llvm точно) по сравнению с GCC, и язык/экосистема имхо куда более непроработаны, чем в прочих популярных языках. Если что-то распараллелить нужно — одним .par или #pragma omp parallel for не обойдёшься. В том же С++ с этим проще. По моему опыту, «эффективный код» и «Delphi» — несовместимы, даже странно слышать эти понятия вместе.


      1. Idot
        16.06.2016 19:14
        +1

        По моему опыту, «эффективный код» и «Delphi» — несовместимы, даже странно слышать эти понятия вместе.

        Смотря, что именно считать эффективностью. По скорости — он, да, не быстрый, и для этого лучше C и C++.

        Но, он крайне эффективен для Rapid Aplication Development — когда нужно быстро получить работоспособный ясно читаемый код работающий без ошибок.


      1. Zealint
        16.06.2016 20:06
        +1

        Знаете, самые разные из класса так называемых «труднорешаемых» задач. Которые в принципе не имеют эффективного алгоритма решения. Классический пример: число незамкнутых маршрутов шахматного коня на доске 8x8. На данный момент считается нерешённой проблемой комбинаторики, однако в моей собственной классификации она находится где-то посередине по сложности. В принципе, решается она не очень сложно, но ни один функциональный язык её не потянет. Можно даже не пытаться. Решать её нужно на кластерах только на Си или Фортране. Конечно, я не говорю о том, что сам программист при этом должен быть очень сильным.

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

        Я думаю, что нет смысла доказывать мою точку зрения, просто выскажу общую мысль всех тех учёных, которые трудились над подобными задачами: функциональщина там не пройдёт ни под каким видом. А нравится это кому-то или нет — нам без разницы: ) Не пройдёт и всё. Никто пока не смог доказать обратного на реальных практических примерах.


        1. Akon32
          17.06.2016 18:45

          Было бы интересно взглянуть на код. (безотносительно споров о функциональщине и языках, тут я наверно соглашусь с вами)


          1. Zealint
            17.06.2016 20:33

            Какой код?


            1. Akon32
              18.06.2016 09:43

              Реализации решения этих ваших задач (если он открытый, естественно).


              1. Zealint
                18.06.2016 10:19

                Это невозможно по целому ряду причин. Одна из них (не самая важная) — весь свой научный код я удалил, когда ушёл из академической науки, осознав за несколько лет трудов, что там ловить нечего. Но есть и другие причины, по которым я всё равно бы его не показал. Самая важная причина — в научных расчётах, особенно новых, не решённых ранее задач, важно, чтобы кто-либо повторил результат независимо. Ответы должны сойтись. Когда даёшь свой код кому-то, гарантия независимости обнуляется, а это недопустимо. Возможно, я ещё вернусь к этим задачам, но без какой-либо связи с государственной наукой.


                1. 0xd34df00d
                  18.06.2016 17:22
                  +3

                  весь свой научный код я удалил

                  Но зачем так делать?


                  1. Zealint
                    18.06.2016 20:01
                    +2

                    Затем, что мне он не нужен. «Учёным», на которых я работал, как выяснилось, тоже, а хранить хлам не люблю. Если вернусь к этим задачам, то в любом случае буду все переписывать начисто, уже с иных позиций и имея больше опыта. Вообще, в моей концепции научной работы программы переписываются с нуля десятки раз, я против классической схемы, когда код пишется один раз и потом только исправляется и дорабатывается, эта позиция не работает в сфере сложных расчётов. Шаг за шагом, удаляя старую программу и создавая новую, мысль совершенствуется. Старая программа даёт некий набор тестовых данных для новой. Новая даёт набор ещё больше — и так далее десятки раз. На третьем четвёртом шаге обычно получается новые научные результаты, но для того, чтобы найти свой предел, итераций требуется гораздо больше. Зачем удалять старую программу? Чтобы не было соблазна забрать оттуда кусок (скопировать или просто подсмотреть, когда забыл), перетащив в новую программу какие-то недостатки.


  1. bentall
    16.06.2016 10:23
    +4

    Императивное программирование (ага, в терминах рецептов/иструкций) и декларативное (в терминах математических определений/стратегий) — два разных способа мышления. Поначалу при обучении программированию математиков (а когда всё начиналось, программировать учили именно их) отучали мыслить математически и учили мыслить алгоритмически. Всерьёз что-то меняться начало только в XXI веке (хотя по разному бывает, SICP вот, наоборот, больше не преподают, хотя он, конечно, не так чтобы совсем уж радикально декларативен).

    Когда в продакшен придёт поколение разработчиков у которых эту мышцу в мозгу наоборот развивали можно будет поговорить, насколько «чистое» функциональное программирование подходит для решения реальных задач и появятся какие-то наработки по оптимальным способам декомпозиции задачи/описании архитектуры ПО. А пока, очевидно, об этом говорить рано.


    1. Idot
      16.06.2016 11:39

      Вроде, эффективное функциональное программирование требует отличного знания Лямбда-исчисления и прочего мат.аппарата => чтобы пришло такое поколение разработчиков необходимо чтобы в ВУЗах такому массово обучали. Вот лично, у меня в ВУЗе не было такого чтобы мы изучали Лямбда-исчисление и тому подобное. Интересно, сколько человек на Хабре могут похвастаться тем, что изучали в ВУЗах нечто подобное (было бы хорошо провести опрос).


      1. lockywolf
        16.06.2016 13:33
        +5

        У меня было лямбда-исчисление в ВУЗе (МФТИ) в качестве одной из модели вычислений. Никак мне это не помогло освоить ФП.

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

        На самом деле, больше всего разобраться со всем этим мешало именно непонимание базовой структуры данных. В императивном языке это массив, тривиально отображающийся к плоской памяти Фон-Неймана. (Или, например, на лист бумаги с ручкой.)
        Хочешь — пиши в него, хочешь — исполняй его пошагово.

        А в ФП какая базовая структура данных? Связный список? Тот самый, в котором доступ по индексу за O(n) осуществляется?


        1. Flammar
          16.06.2016 14:06

          Односвязный список;-) который хорош прежде всего тем, что к одному «хвосту» можно «присобачить» несколько «голов», благо всё реализуется через указатели. А не нужные «головы» потом уберёт сборщик мусора.


        1. 0xd34df00d
          17.06.2016 04:58

          Опа, а вы какой факультет и год выпуска? У меня на фупме с 2014 годом не было :(


  1. Shamov
    16.06.2016 11:02
    +6

    Если бы ему нужно было приготовить не один пирог, а, скажем, десять тысяч одинаковых пирогов силами 946 пекарей, в распоряжении которых имеются 234 духовки (из которых одновременно в сеть можно включить только 178)… 534 противня… 421 миска… 765 миксеров… 124 измельчителя для орехов и… 511 полотенец для остывания, то ему бы в любом случае пришлось преобразовать рецепт к функциональному виду, полностью отделив шаги приготовления от текущего состояния пирога. В противном случае пекари тратили бы слишком много времени на непродуктивное ожидание между выполнением отдельных шагов алгоритма.

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


    1. Idot
      16.06.2016 11:55

      А Event-Driven программирование разве в этом случае не подойдёт?
      — Event освободилась ёмкость для замешивания теста => месим тесто
      — Event освободилась форма пирога => заливаем в него тесто итп
      — Event освободилась духовка => ставим туда форму с пирогом
      — Event пирог испёкся => освобождаем духовку и форму для пирога
      ну и так далее в том же духе.
      Причём всё логично и легко понятно, а на События можно реагировать процедурно.


      1. Shamov
        16.06.2016 12:15
        +4

        Event-Driven — это, как бы, lite-версия ФП. Для тех, кто уже хочет отделить шаги алгоритма от состояния, но ещё не готов к хардкору.

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

        В одном из последних номеров Overload как раз была статья о том, как можно постепенно приучить нормальных программистов к функциональной парадигме через event-driven и конечные автоматы (http://accu.org/index.php/journals/2199).


        1. Idot
          16.06.2016 19:44

          Спасибо за полезную ссылку.

          PS Думаю, что если Вы переведёте, то получите плюсы в карму. :)


          1. Shamov
            16.06.2016 21:09

            А я думаю, что у меня есть более интересные дела :) Но, на самом деле, автор статьи русскоговорящий. Возможно, у него можно попросить готовый русский текст и выдать его за перевод. Не исключено, что изначально статья была на русском, а на английский была переведена.


            1. Idot
              17.06.2016 04:00

              Я читаю, по английски (и не только читаю). Я про то что Вашей Карме на Хабре очень пригодились бы плюсы за перевод. :)


              1. Shamov
                17.06.2016 06:31
                +1

                Я не парюсь насчёт кармы. Я уже взрослый.


                1. Idot
                  17.06.2016 07:24

                  Можно было бы не париться, если бы на Хабре при падении Кармы, не возникали бы ограничения на количество сообщений — сначала 1 сообщение в час, затем 1 сообщение в день, потом 1 сообщение в неделю, и так далее. Если у Вас нет ни одной статьи, то Вашу карму можно только минусовать.


                  1. Shamov
                    17.06.2016 07:40

                    Много лет я вообще не мог писать сообщения. Эта возможность по необъяснимой причине открылась совсем недавно. И ничего. Как-то жил с этим. Более того, так даже лучше было. Не нужно было ни писать комментарии, ни отвечать на ответы. Хорошее было время.


                  1. MaximChistov
                    17.06.2016 08:57
                    +1

                    >Если у Вас нет ни одной статьи, то Вашу карму можно только минусовать

                    Неа, можно плюсовать до +4


                    1. Idot
                      17.06.2016 18:24

                      Что-то впервые такое слышу. И не вижу, чтобы кто-то плюсанул Shamov'у за его полезную ссылку для желающих ознакомиться с ФП. Где такое в правилах?


                      1. Mingun
                        17.06.2016 18:29

                        Недавно ввели. По итогам вот этой ветки обсуждения.


                      1. MaximChistov
                        17.06.2016 18:33

                        https://geektimes.ru/company/tm/blog/276278/
                        Да и проверить просто — у людей без публикации не только красная стрелочка теперь.


  1. saluev
    16.06.2016 11:03
    +3

    На секундочку, автор мог бы сделать

    bool success = false;
    ParseResult<V> result;
    using expand_variadic_pack  = int[]; // фокус!
    (void)expand_variadic_pack{0, ((success = success || (
            parsers.parse(state).get_success()
        && ((result = ParseSuccess<V>{
                {std::move(parsers.parse(state).get_success()->value)},
                parsers.parse(state).get_success()->new_state
            }), void(), 1)
    )), 0)... };
    
    и обойтись без рекурсии. Страшновато, конечно, но если parser.parse принимает const State&, то компилятор, возможно, даже соптимизирует три одинаковых вызова parsers.parse(state).get_success() в приведённом коде.
    (Объяснение происходящего на SO)


  1. PretorDH
    16.06.2016 11:55

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

    Где проще использовать функциональный язык зависит только от сферы применения и расширяемости конкретной задачи.

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

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

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


  1. k12th
    16.06.2016 11:59
    +5

    Функциональное програмирование странное по одной-единственной причине: оно… странное. Потому что в школах учат бейсику/паскалю, а в вузах плюсам и джаве.


    Если взять, так сказать, Маугли от программирования и воспитать его исключительно на хаскеле/ML (предположим, лисп-машину кто-то построил и императивных процессоров наш лягушонок не видит), никаких проблем с ФП у него не будет, а когда ему в 25 покажут джаву, он, конечно, сначала малость прифигеет, потом скажет, что это придумали какие-то инопланетяне, потом проникнется и скажет, что это клевый способ решить некоторые проблемы, которые в хаскеле выходят не слишком красиво. И, в конце концов, придет к выводу, что лучше всего сочетать два подхода:)


    1. Idot
      16.06.2016 12:00

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


      1. k12th
        16.06.2016 12:02
        +2

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


      1. folkyatina
        16.06.2016 14:38

        А чего это он стал функциональным и когда?


        1. Idot
          16.06.2016 15:15

          Потому что основан на LISP.


          1. EvilBlueBeaver
            16.06.2016 15:42

            А LISP у нас функциональный уже? И какой именно язык из семейства LISP? А то что-то в CL, например, объектно-ориентированности и императивности полным-полно


            1. Idot
              16.06.2016 19:16
              +2

              O_O а давно уже LISP перестал быть функциональным? *в офигении*

              PS язык Logo появился в 1967 году на основе классического LISP.


              1. EvilBlueBeaver
                16.06.2016 20:35

                Да, он мультипарадигменный, например, вот

                (defparameter *my-hash* (make-hash-table))
                (setf (gethash 'one-entry *my-hash*) "one")
                

                или вот
                (defclass person ()
                  ((name :accessor person-name
                         :initform 'bill
                         :initarg :name)
                   (age :accessor person-age
                        :initform 10
                        :initarg :age)))
                
                (setq p1 (make-instance 'person :age 100))
                (setf (person-age p1) 101)
                

                Да, в нем можно писать в функциональном стиле. Ровно так же можно писать и в каком-нибудь C#, но тот функциональным не становится.
                Собственно даже из университетского курса ФЛП помню, что никто не заморачивался в лиспе с функциональщиной, рекурсиями, свертками и прочим. Все тупо бахали setf и циклы, а преподу было наплевать, ведь сказали же, что лисп функциональный, значит все нормально.


                1. Idot
                  17.06.2016 04:20
                  +1

                  Функциональность появилась в LISP раньше, чем появился сам C#, и LISP традиционно относят к функциональным языкам. И даже для него специально создавали «LISP-машины» именно специально для функционального программирования.


  1. warlock13
    16.06.2016 12:09
    +2

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


    Может быть вы мало программировали на нормальных функциональных языках? У нас есть один изменяемый объект (пирог), над которым совершается множество действий, переводящих его из одного состояния в другое… да это же монада State как она есть!


    1. Bas1l
      16.06.2016 12:38

      Справедливости ради, программировал не я, а автор оригинала, но ваш пример, на мой взгляд, созвучен идее статьи. Чтоб записать простой рецепт, мне нужно разобраться с монадами и с монадой State. Вы серьезно? То есть, получается, в обоих языках нужно будет выучить структуры/алгебраические типы данных (если типов пирога и т.п. под рукой нет). Нужно будет научиться писать или хотя бы использовать методы/функции (разогреть, смешать). Но в ФП еще вот, пожалуйста, теорию категорий, монады, монаду State. Вот в этом, собственно, и проблема (и причина даже описана в статье—ФП оказывается слишком далеко от реальности, от типичных моделей, с которыми работает мозг и от работы машины).


      1. VoidEx
        16.06.2016 13:16
        +1

        Во-первых, чтобы разобраться со State для практического применения, вовсе не надо «теорию категорий» и даже «монады» в математическом их смысле.
        Во-вторых, вы, вероятно, полагаете, что всё, что вы перечислили, необходимое к обучению и в императивном языке, оно значительно проще, чем State, и потому добавление State — та соломинка, что переломит хребет верблюду?


        1. kreslavsky
          16.06.2016 17:20

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


          Итак, начнём.


          def разогретьДуховку: (Духовка, T) => Future(РазогретаяДуховка)
          
          def подготовитьПротивень: (Противень, Мука) => Future(ПодготовленныйПротивень)
          
          def подготовитьОсновуДляТеста: (Мука, Сода, Соль) => Future(ОсноваДляТеста)
          
          def приготовитьЗаправку: (Масло, Сахар, КоричневыйСахар, Яйца, Бананы) => Future(Заправка)
          
          def приготовитьТесто: (ОсноваДляТеста, Заправка, Кефир, Орехи) => Future(Тесто)
          
          def выпечь: (ПодготовленныйПротивень, РазогретаяДуховка, Тесто, Время) => Future(ГорячийПирог)
          
          def остудить: (ГорячийПирог, Полотенце, T) => Future(ГотовыйПирог)
          
          let холоднаяДуховка = Духовка()
          let чистыйПротивень = Противень()
          let масло = Масло(450г)
          let сода = Сода(1ч.л.)
          let cоль = Соль(1ч.л.)
          ... etc
          
          let пирог = for {
              духовка <- разогретьДуховку(холоднаяДуховка,175)
              противень <- подготовитьПротивень(чистыйПротивень, Мука(50г))
              основа <- подготовитьОсновуДляТеста(...)
              заправка <- приготовитьЗаправку(...)
              тесто <- приготовитьТесто(основа, заправка, Кефир(200г), Орехи(50г))
              горячийПирог <- выпечь(противень, духовка, тесто, 30мин)
              пирог <- остудить(горячийПирог, Полотенце(), 25)
          } yield пирог

          Сложно?


          1. atc
            16.06.2016 17:40
            +2

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


            1. kreslavsky
              16.06.2016 18:10

              В данном случае задачу можно разделить на вычисления и эффекты. Для реализации необходимых эффектов мы просто используем соответствующую монаду. Или их комбинацию.
              Что мы получаем:


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

              Если принять, что мы при этом использовали подход Domain Driven Design, то часть сложных эффектов явно выходит за рамки нашего Bounded Context и у нас сводится к публикации соответствующего Business Event.


              Как-то так. Кстати, если мы про реальный мир, то там не обойтись без обработки ошибок. Добавим:


                  пирог
                      .map(УпакованныйПирог(пирог))
                      .recover{
                           case Подгорел() => ....
                           case Непропёкся() => ...
                           case ОтключилиЭлектричество() =>...
                           case НахамилНачальник() => ...
                           default => ...
                      }

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


  1. Flammar
    16.06.2016 13:28

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


    1. FForth
      17.06.2016 20:00

      Один из вариантов язык Factor?


  1. igrishaev
    16.06.2016 14:13
    +1

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


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


  1. csbubbles
    16.06.2016 14:20
    +2

    Мне кажется, что идея функциональных языков как раз в упрощении описания задачи.

    Типа:

    (достать (печь (поставить пирог в (разогреть духовку до 175 градусов)) в течение 30 минут))

    или

    (достать (выпеченный (поставленный пирог в (разогретую духовку до 175 градусов)) в течение 30 минут))

    Наиболее используемая скобочная нотация, возможно, не лучший DSL для описания задач, но, тем не менее, мне кажется, то, что описано в статье, не совсем правильно применять к реалиям функциональных языков. Я боюсь, что видение «головоломок» в функциональных языках происходит обычно от того, что люди пытаются применить к нему подходы, к которым они просто привыкли в процедурных или ОО языках. Но это как разговаривать на русском языке, заменяя слова английскими — речь от этого не станет английской. Это, скорее, просто разные способы мышления и подходы в постановке и обработке задач. Сложнее или проще для восприятия (лучше/хуже) — зависит во многом от опыта работы с конкретными языками и методик решения задач.

    PS Как еще один вариант в абстрактной (не в LISP) нотации:

    достать из печи тесто после того как оно
    . простояло в течение 30 минут в
    … разогретой до 175 градусов духовке


  1. maxfox
    16.06.2016 14:20
    +1

    Мне кажется, автор статьи в своей кулинарной аналогии не совсем честен. Императивная форма рецепта не полна… Интерфейс взаимодействия с духовкой? Размер противня? Какое масло? Какая мука? Как и чем взбивать? «А ну его к черту — я не могу это закончить!». Беда в том, что императивный рецепт может быть полезен лишь исполнителю-человеку, обладающему кулинарным опытом. При этом результат всегда будет разным в зависимости от исполнителя. Ну мы, конечно, покроем пирог автоматическими тестами, напишем полифилы для поваров-левшей и разработаем упрощенную версию для морально устаревших кондитеров. Мне кажется, что если подходить к разработке ответственно, то хрен редьки не слаще. Просто в случае императивного подхода часто забывают о том что работоспособность программы при любых входных данных неплохо бы доказать формально. А тут мы уже приходим к математической модели. Ну а если раз-два и в продакшен — то ФП, конечно, лишняя трата времени.
    Ну и еще, как мне кажется, ФП не популярно не потому что оно странное (странных технологий немало), а потому что сильно отличается от того, подо что инфраструктура затачивалась десятилетиями. При наличии всесторонней поддержки — ОС, библиотеки, умные компиляторы, может быть даже железо — ФП может радикально повысить качество прикладного ПО.


  1. guai
    16.06.2016 15:18

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


  1. Flammar
    16.06.2016 15:57
    +2

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


    1. kreslavsky
      16.06.2016 17:28
      +2

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


    1. VolCh
      16.06.2016 18:30

      Алгоритм, да, — по определению подразумевает императивность. Но вот изменяемое состояние — нет, в общем случае это деталь реализации исполнителя. А программирование не подразумевает даже императивности.


  1. j3fe
    16.06.2016 17:01

    Может, декларативное программирование без использования функций (не ФП), как базовой сущности может лучше проявить достоинства декларативных алгоритмов. Например, если брать vhdl, можно увидеть как декларативно описываются модули (узлы электрической схемы, вентили и регистры, входы/выходы), и всё описание системы представляет её слепок в один момент времени. Дальше мы добавляем исполнение всей схемы за один такт и когда такты следуют друг за другом, мы получаем работу тех или иных алгоритмов. А ещё все забывают про SQL, как пример декларативного языка. А через такие простые для понимания системы мы можем перейти к пониманию ФП.


    1. VolCh
      16.06.2016 18:33

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


      1. j3fe
        16.06.2016 19:34
        +2

        Потому что это непошаговое описание содержимого результата. То есть, это ЧТО, а не КАК.
        Но это не о хранимках, конечно.


  1. Azoh
    16.06.2016 17:14
    +2

    Пример с парсером неудачный. Выглядит это так:
    1. Было у меня повторение кода. Плохо, плохо, нужно отрефакторить
    2. Что-бы применить? М-м-м, мы же на плюсах пишем, шаблоны же
    3. Какая боль, какая боль, шаблоны функциональные
    4. Получилось костыльно

    ?.. Это все функциональщина проклятая
    ?+1. Я не против функциональных языков, но пускай там все будет как в императивных

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


  1. IvanPanfilov
    16.06.2016 18:05
    -3

    > Так уж оказалось, что шаблоны С++ — это функциональный язык

    Афтар сделал мой день

    > Функциональное программирование непопулярно, потому что оно странное

    оно не странное. это чуваки которые пытаются чтото функциональное изобразить на не функциональных языках — странные.

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


    1. VoidEx
      16.06.2016 18:18
      +2

      >> Так уж оказалось, что шаблоны С++ — это функциональный язык

      > Афтар сделал мой день

      Ну, вообще-то именно так, чистое ФП. Напишите на шаблонах compile-time факториал.


    1. 0xd34df00d
      17.06.2016 05:03

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

      А ещё у вас аватарка такая… хорошая-хорошая!


  1. thousandsofthem
    16.06.2016 19:44
    +1

    Более менее реальный код, написанный на elixir — который вполне себе функциональный, с иммутабельными переменными т тэ пэ:

    ```
    pan = pan
    |> grease
    |> flour

    oven = oven
    |> preheat(«175C»)

    dough = mix(«flour», «baking soda», «salt»)

    cake_mixture = mix(«butter», «white», «sugar»,«brown sugar»)
    |> beat_until_fluffy
    |> beat_mixed_with(«eggs»)
    |> mixed_with(«bananas»)
    |> mixed_with(:alternating, «buttermilk», dough)
    |> mixed_with(:chopped, «walnuts»)

    cake = cake_mixture
    |> place_on(pan)
    |> put_in(oven)
    |> wait_for(«30min»)
    |> eject
    |> put_on(:towel)
    |> wait_until_cool_down
    ```

    Как видим, вся последовательность операций линейна и понятна. Может быть это «недостаточно функционально»? Пофиг, главное что удобно на практике.

    P.S. |> это pipe operator, работает так:
    a |> b |> c ==> c(b(a()))


  1. 77vlad
    16.06.2016 21:04
    +2

    Те кто здесь рассуждает о функциональном подходе, то забывает о главном, что лямбда исчисление эквивалентно машине тьюринга. Таким образом, выразительная и вычислительная мощь императивных и функциональных языков ОДИНАКОВА!
    Но есть ньюанс, никто не знает как должна выглядеть архитектура функционального фычислителя ввиду его полной абстракции ;)
    Зато существует, уже полвека, неймановская архетиктура и все императивные языки являются надстройкой над этой архитектурой и максимально ее утилизируют. Все Функциональные языки являются надстройкой над виртуальной машиной, которая пишется в императивном стиле и использует реальную неймановскую архетикоуру.
    Так что функциональные языки это попытка построить еще один уровень абстракции над императивным языком, а императивный язык это уровень абстракции над ассемблером и тд и тп
    Вопрос риторический сколько уровней абстракции нужно для решения конкретной задачи. Как то так


    1. warlock13
      16.06.2016 22:47

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


      "никто не знает как должна выглядеть" /= "не может существовать"
      Все Функциональные языки являются надстройкой над виртуальной машиной


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


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


      1. 77vlad
        16.06.2016 23:42

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


        1. warlock13
          17.06.2016 01:14

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


          1. 77vlad
            17.06.2016 07:39
            +2

            И что это принципиально меняет? Все равно используется неймановская архетиктура и императивный язык, а какие пляски с бубном начинаются при реализации много поточности и сборки мусора!
            Так зачем, если не видно разницы, думать больше!? Сразу пишем на императивном языке ;)
            Как правильно заметил автор, 95 процентов задач вполне решаются императивным подходом, плюс нароботана десяти-двадцатилетняя экспертиза по решению, плюс библиотеки


    1. develop7
      16.06.2016 22:49

      никто не знает как должна выглядеть архитектура функционального фычислителя ввиду его полной абстракции ;)


      всё правильно, за исключением того, что таки знают как минимум один раз — https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/GeneratedCode


      1. 77vlad
        16.06.2016 23:36

        Вы привели пример реализации на неймановской архетиктуре и императивном языке. Я знаю еще несколько различных ИМПЕРАТИВНЫХ реализаций. Фактически функциональное программирование это синтаксический сахар над алголоподобными языками. Мое утверждение было гораздо более общим, архетиктура выч системы должна из коробки поддерживать функциональное программирование. Пока есть пример лисп-машины, но она тоже неймановская.
        В реализации сила и слабость функционального языка, ибо с одной стороны язык не запрещает никаких способов реализации которые бы давали правильный ответ, но и никаким образом не подсказывает, какая реализация могла бы быть опимальной. Вся реализация лямбда исчисления и фп — математические концепции в голове разработчика.


    1. Idot
      17.06.2016 04:02

      никто не знает как должна выглядеть архитектура функционального фычислителя ввиду его полной абстракции ;)

      А что не так с вариантом?
      — берём функциональный код f(a,b)
      — а затем преобразуем получая вот такое a b f
      => получился Forth! Который, по скорости вполне сравним с C => PROFIT!

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


      1. VolCh
        17.06.2016 05:42

        А есть FORTH-машины на не неймановской архитектуре?


      1. 77vlad
        17.06.2016 07:43

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


        1. Idot
          17.06.2016 07:48

          А как сейчас пишут? (поскольку, на функциональных языках не пишу, то мне стало очень любопытно)


          1. 77vlad
            17.06.2016 12:15

            да так и пишут if — then — goto только называют это всякими новомодными словечками ;)


  1. 77vlad
    17.06.2016 07:50

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


    1. napa3um
      17.06.2016 08:06
      +2

      Функция из десяти тысяч строк? Вам ни ФП, ни ООП не поможет, лучше заняться чем-нибудь другим, не программированием.


      1. Idot
        17.06.2016 10:03

        Legacy-Code — не вариант?


        1. napa3um
          17.06.2016 10:19

          Можно придумать множество оправданий самым нелепым явлениям. Но заниматься этим пользы мало.


          1. Idot
            17.06.2016 10:28
            +1

            Увы, вполне вариант. Бывает, что нужно искать ошибку в коде, написанном уже ушедшим сотрудником. И бывает, что цельный кусок в 5тыс. строк распутать и понять оказывается легче, чем лапшу в два-три десятка функций и процедур общим объёмом в тысячу строк. Тупо потому что все эти 5тыс. все — в одном месте, прямо перед глазами. А два-три десятка мелких функций и процедур приходится искать с матом по различным зависимостям. И да, legacy-code не обязательно старше десятка лет, ему вполне может быть два-три года, просто, он остался от человека уже покинувшего кампанию.


            1. napa3um
              17.06.2016 10:30
              +1

              У вас очень хорошая фантазия.


              1. Idot
                17.06.2016 10:46
                +1

                Нет, это Вы просто не получали legacy-code.


                1. 0xd34df00d
                  18.06.2016 00:38

                  Я получал. Функции на пять тысяч строк распутывать таки на порядки труднее.


      1. 77vlad
        17.06.2016 11:56

        Много раз сталкивался с такими функциями самый эпичный случай хранимая процедура на t-sql из 8 или 9 тыс строк и не одна, великий и могучий индусский код


    1. warlock13
      17.06.2016 11:16

      То есть концептуально, для разработки сложных систем, ничего не поменялось


      Нет. Разница огромная: при функциональном подходе эта навороченная функция из 10000 строк чистая, и она имеет точно специфицированный вход и выход. Это резко упрощает работу с ней.
      Например, вы можете сначала посмотреть на эту функцию как на чёрный ящик и написать на неё тесты (причём именно и только на эту функцию), после чего заняться сколь угодно «опасным» рефакторингом без риска что-нибудь сломать. Или выяснить, что функция работает неправильно только при определённом сочетании входных параметров и пофиксить это приписыванием затычки-обёртки, вообще не залезая в это болото, и при этом, в отличие от императивного программирования, есть хороший шанс, что это будет работать.


      1. 77vlad
        17.06.2016 12:12
        +3

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

        А вообще, сколько раз (за двадцать лет программирования) я уже слышал о «новых прорывных» технологиях, которые сделают хорошо программисту, а воз и ныне там… уже не верю ни в серебряные пули, ни в эльфов из Микрософт, что выкуют новую ОС и язык программирования всеобщего счастья, как-то так.

        Да и функциональное программирование живет себе уже 40 лет и уже десятое поколение начинающих программистов-фанатиков обещает всеобщее счастье и прогресс, реальность топчет все эти обещания кованным сапогом… в итоге имеем промышленный стандарт с++\c# и Java в которых что-то можно описывать в функциональной парадигме посреди императивного кода


        1. warlock13
          18.06.2016 17:24
          +1

          наоборот там будет чистый фарш из десятка монад, зависимостей и состояний


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


  1. akamensky
    17.06.2016 12:24
    -1

    На самом деле ООП это абстракция над функциями. Процессор не знает ничего про ООП и на стадии компиляции все объекты и их методы преобразуются в набор функций (на самом деле даже не функций а под-программ с набором условных или безусловных переходов).

    И мне кажется непопулярность ФП это в некотором роде выдумка. Если писать огромную систему документооборота (например), то в этом случае без ООП не обойтись. А если писать например утилиту для системного администрирования, которая уместиться в один файл, то ООП это overkill.

    ООП и ФП это просто инструменты которые нужно правильно применять. И право на существование имеют оба подхода.


    1. VolCh
      17.06.2016 13:19
      +2

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


  1. vlad72
    17.06.2016 12:25

    А ну покритикуйте…

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

    Потом появилась необходимость сохранять состояния (чтобы вызывать их и обрабатывать в любой момент) — появилось ООП со следующими особенностями:
    — частичная многопоточность,
    — сохраняемые состояния,
    — отсутствие доступа к чистым функциям (которые оказались инкасулированны внутри объектов, «загрязненных» состояниями).

    Потом стало нехватать многопоточности и вспомнили про ФП, где есть:
    — доступ к чистым функциям (конечно, функции сами по себе всегда чисты, но так уж повелось),
    — неограниченная многопоточность,
    — отсутствие состояний.

    Можно конечно «в лоб» объединить ООП и ФП в одном языке, но почему бы не поступить так:
    — есть чистые функции (как в ФП),
    — есть недо-объекты (в которых хранятся только данные), назовем их Н-объекты (они являются только носителями состояний),
    — Н-объекты вызывают чистые функции, которые передают выходные данные в: вызывающий Н-объект; другой Н-объект; другую функцию.

    Получаем два множества сущностей, в одном — Н-объекты, в другом — чистые функции. Можно переходить к графическому программированию, где отношения между ними будут задаваться в виде схемы (что будет очень наглядно, быстро и надежно).


    1. 77vlad
      17.06.2016 13:08
      +2

      Ага! Гладко было на бумаге… как только заговорили о многопоточности решили все разделить по функциям, а потом вспомнили о синхронизации, а как ее осуществлять из чистых то функций!? Опять неймановская архетиктура стала из под абстракций торчать

      ООП и ФП вообще разные вещи и никак друг-другу не противоречат.


      1. vlad72
        17.06.2016 15:08

        Вот именно, что подходы не противоречат, а ЯП бодаются.


        1. VolCh
          17.06.2016 15:22

          Да и ЯП нынче обычно поддерживают несколько парадигм. Бодаются программисты прежде всего :)


          1. vlad72
            17.06.2016 19:00

            Если бы только программисты — создатели ЯП и те бодаются…


    1. VolCh
      17.06.2016 13:30

      Значит, вначале был императивный подход с такими особенностями:

      — отсутствие хранимых состояний,
      ...


      Когда такое было? На ткацких станках с перфократами?


      1. vlad72
        17.06.2016 15:44

        Ну и это тоже…


  1. 77vlad
    17.06.2016 13:36
    +1

    А кстати, давайте снимем последние покровы!!! Нахрен

    Чистота функций в ФП млять… Какая нах… чистота функций может быть, если все реализуется на императивной неймановском процессоре!? Какая, я вас спрашиваю!?

    Если вы в коде на haskel не написали, var a = 100001 или там a+=500, это еще не значит, что ваш код пахнет ромашками, а у соседа пишущего на c++, пардон, г… м.

    А стеки вызовов функций? А указатели на голову и хвосты? А стеки данных и буферы потоков ввода/вывода? Вы думаете этого всего нет в haskel!? Тогда купите себе билет в дурдом и больше не пишите го… код!

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

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

    И любой разработчик, не зная всех особенностей реализации, может безобидной функцией на ФП языке завалить всю систему в глубокий дос. Плавали — знаем, на C# такой сценарий как два пальца, а если быдлокодеру дать еще и haskel с clojure — туши свет


    1. napa3um
      17.06.2016 14:07
      +4

      Чистота функций в ФП математическая, в голове программиста, проектирующего на нём информационную систему и контролирующего сложность проекта, а не в исполняющей среде. Чистота нужна не для того, чтобы убеждать себя в чистоте исполняющей среды, а как раз для того, чтобы декомпозировать систему на максимально независимые блоки в условиях «грязного» (физического) исполнителя. Т.е., для некоторых гарантий относительно того, куда грязь не затечёт. Все эти ООП, ФП, КОП, АОП, КПСС — лишь способ отыскать наиболее удачные «линии разреза» системы для разложения на малозависимые и удобно поддерживаемые блоки кода, а не для того, чтобы устраивать религиозные войны на тему выбора единственного божественного пути. Вы воюете не с ФП, а с чучелом, которое сами придумали.


      1. 77vlad
        17.06.2016 14:26
        -1

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


        1. napa3um
          17.06.2016 14:39
          +5

          Вы из тех, кто программирует на процессоре, а не на ЯП? Да, ФП — это именно абстрактно и здорово, и, конечно, оно нужно далеко не всем и не всегда, а только тогда, когда такая абстракция уменьшает совокупную сложность. Это именно вы видите лишь две крайности — либо всё ФП, либо всё ООП и никак иначе. Представляю, каким было ваше возмущение о существовании сортировки пузырьком, когда вы узнали о сортировке слиянием.