Pull to refresh

Comments 320

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

Хаскель подходит для промышленных задач, и люди, которые его используют именно так, очень недоумевают по поводу мифов, в том числе и приведенных вами.
UFO just landed and posted this here
Это сейчас серьёзно было?
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.
ну так это они описывают то, что хотели, а не то, что получилось
Читаем ещё раз тезис «той области, для которой был создан — в теории категорий». По ссылке сказано, что это, мягко говоря, не так.
Ваша правда, может они и создавали его не только для академических проектов. Но гляньте на список авторов — там же сплошная академия, всего один человек от индустрии. Академики пишут академические проекты, говорю как участник одного из них.
А в чем проблема со сборкой?
Для немонадических «маленьких частей» все вообще очевидно. Композиция функций с возможным добавлением прослоек с преобразованиями типов.
С монадическими или стрелочными «частями» надо смотреть. Если монады не покидают границ модуля, как в первом случае. Если это простая монада, которую можно «запустить» (типа парсера), тоже обычно все просто. Если там IO или STM, то применять их можно только в другом монадическом коде — но это получается мало отличается от обычного императивного программирования.
С производительностью проблемы могут возникнуть из-за ленивости — долго работающие программы могут накапливать в памяти недовычисленные данные.
Искать эту проблему бывает не просто, но возникает она когда все остальное уже работает.
И отлаживать ленивость труднее…
Мне очень мало приходилось отлаживать программы Haskell — если они компилировались, почти всегда работали.
А вот привычка к ленивости при переходе на C++ и Scala принесла необходимость отлаживать инициализацию взаимозависимых объектов. В ленивом языке с этим было проще.
UFO just landed and posted this here
UFO just landed and posted this here
Да блин, хватит упарываться уже. К чему эта сугубая религиозность: ФП, ООП, это все мелочи. ФП и ООП это всего лишь инструменты для построения абстракции. Мы ж не спорим чо круче пила или молоток. ФП — небольшие функции для обработки состояния без сохранения состояния. ООП — хранение состояния системы во время всего жизненного цикла. Зачем противопоставлять эти концепции? Они ж взаимодополняют друг друга?

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

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

class NumberState {
  int a;
  int b;
}


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

Для того, чтобы поддерживать систему и дальше. даже если она будет очень сложной — используйте Dependency Injection. Таким образом вы не будете сами инстанцировать классы, вы будете только указывать каким образом это сделать и какие зависимости должны быть прокинуты. Так можно расширять контракт без потери обратной совместимости на уровне входных данных. Мы не должны зависеть от атомарных типов. Мы должны зависеть от абстракций.
Таким образом мы можем добавить еще несколько состояний при этом даже не нарушив внешний контракт при условии, что мы возвращаем корректно значение:
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.
> Таким образом все состояние над которым мы производим операции можно протестировать, потому что мы его задаем только в конструкторе

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

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

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


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

Важное правило — читает любой, пишет только через внешние методы. О том, как лучше уже реализовывать эти внешние методы, это уже зависит от каждой конкретной команды. Кто-то на конвенциях может договориться. А кому-то нужна большая абстракция, чтобы максимально вывернуть руки.
Вопрос, а зачем их разделять — у нас и так есть совокупность полей и совокупность поведения? Можно посмотреть какой-нибудь менее абстрактный пример
Разделить данные и изменяющие их функции (не изменяющие функции в общем случае лучше оставить с данными) — наиболее простой способ обеспечить отсутствие неявных изменений данных. Грубо, если мы вызываем какие-то методы объекта класса SomeObject, то можем быть уверенны, что они не изменяют его состояния, а если вызываем методы объекта класса SomeObjectManager, то уверены, что изменяют (или создают/удаляют).
UFO just landed and posted this here
«Наиболее простой» не значит «единственный». Это вопрос соглашений в команде, например вопрос именования. В целом нужно избегать создание методов, которые и возвращают данные, и изменяют их (исключение — различные методики кеширования). Грубо — разбивать их на геттеры и сеттеры, функции и процедуры, запросы и команды.
Применительно к ООП мне эта концепция кажется странноватой — разве там не основной принцип, что состояние должно быть вообще абстрагированно и мы не можем получить к нему прямой доступ?


Это извращенная трактовка принципа инкапсуляции, отождествляющая её с сокрытием. Инкапсуляция — это не сокрытие данных от внешнего мира, а объединение логически связанных данных и функций в единое целое.
С моей точки зрения, это полезное извращение — когда снаружи не видно, что есть данные а что есть алгоритмы для получения каких-то свойств, мы можем менять реализацию гарантированно не затрагивая пользователей
Сейчас вы говорите уже и не о инкапсуляции, и не о сокрытии, а о замене реализации — это совсем другой вопрос. Сокрытие по сути решает лишь одну задачу — отделение публичного интерфейса от внутреннего. Но эту задачу можно, как правило, решить множеством способов. Но в общем случае ни один из них не гарантирует, что пользователи не будут затронуты — очень часто они рассчитывают не только на формальную сигнатуру интерфейса, но и на определенное поведение, например, что после вызова setA(5), getA() будет возвращать 5, а не 0 или 100500.
Это вопрос в определении контракта.
Сокрытие никак не относится к контракту. Максимум можно считать, что сокрытие один из механизмов обеспечения публичного контракта. Вспомогательный, уменьшающий вероятность случайного нарушения контракта.
Определение контракта это как раз отделение интерфейса в общем виде от деталей реализации. В частности сокрытие реальной структуры состояния
Сокрытие реальной структуры состояния в общем случае ортогонально контракту. Если мы не описали в контракте какую-то важную переменную, то будь она хоть глобальной, не говоря о публичной, то никто ей не имеет права трогать. Принцип контрактного программирования: всё, что не разрешено (не описано в контракте) — запрещено. Это с одной стороны. А с другой, я могу описать в контракте приватную переменную и рекомендовать её получать/изменять через отражения, прямой доступ к памяти и т.п.
Побольше вам таких контрактов :)!
Это была трактовка не инкапсуляции, а, скорее, CQRS.
Статья, на мой взгляд—в первую очередь попытка рефлексии на тему того, почему же ФП непопулярно. Потому что по объективным критериям функциональные языки, действительно, совсем не популярны. Хотя, как и написано во вступлении, считается, что у них куча преимуществ. Действительно, и следить за состоянием легко, и параллелить как бы легко, и математически красивые и т.п. Но на них никто не пишет. Взять, к примеру, TIOBE index (конечно, он не совершенен, но хоть какой-то). В первой двадцатке нет ни одного функционального языка. И идея автора показалась мне очень хорошей, и пример с пирогом метким. Да, действительно, судя по всему, функциональные языки просто слишком далеки (i) от моделей реального мира, (ii) от моделей задач, что появляются в головах программистов, и (iii) от того, как работает компьютер. Что изменяемое состояние—это то, что близко реальному миру, человеку, компьютеру.

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

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

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

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

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

В качестве контраргумента могу предложить перечислить крупные opensource проекты, которые написаны преимущественно с fp подходом.
«Любая достаточно сложная программа на C или Фортране содержит заново написанную, неспецифицированную, глючную и медленную реализацию половины языка Common Lisp.»
Но все же хотелось бы увидеть примеры «космических кораблей на fp», в подтверждение вашего предыдущего высказывания, так как мне таковые еще не встречались.
У вас всё ещё впереди. Это моё мнение, не стОит пытаться выпрашивать формальный «пруф», можете не принимать моё мнение или принимать противоположное моему — ваше право.
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 )
Как только у вас будет массив (список!) NumberState, с которыми надо что-то сделать в чистом ФП—все, пиши пропало. А если еще и операций будет несколько, тоже в списке…

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


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

Что? Отфильтровать, свернуть, отразить?
UFO just landed and posted this here
staticlab > По сути, полноценный SPA-фронтенд вполне можно написать, например, на React/Redux, пользуясь только функциональными инструментами…

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

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

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

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

Redux vs Mobx -> ФП vs ООП — Mobx одержит победу, имхо ;-)
UFO just landed and posted this here
В React из ФП есть в виде stateless components

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

Как минимум необходимость this.setState полностью разрушает чистоту ;) А вообще на практике при сложной модели такая связка скорее становится процедурной, чем функциональной.
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
Когда речь идёт о связке с Redux, зачем вам вообще понадобилось трогать setState? Вы скорее всего что-то делаете не так.
С другой стороны, в реальном мире мы не можем перевести состояние пирога из «приготовленный» в «готовый» без совершения каких-то операций, а в императивном программировании это (прямое задание состояния) сплошь и рядом, что доставляет другую боль. Объединяет два мира принцип: состояние программы (модуля, объекта) нельзя изменить, можно лишь применить к нему «мутирующую» функцию (часто с дополнительными аргументами) и получить новое состояние. Или применить к состоянию «обычную» функцию (часто без аргументов), чтобы получить как
Мне кажется, различие только в том, что в императивном мире есть глобальное общеизвестное состояние в объектно-оритетированном мире у объектов есть identity и state, соответственно, есть понятие изменения как для глобального объекта «мир» так и для любого конкретного объекта (а чтобы объяснить, что состояние неизменно, нужны спецухищрения). Причем состояния объектов являются частью состояния мира.

В чистом функциональном мире наоборот, эти понятия вводятся дополнительно и локально: если хочешь использовать глобальное состояние надо явно использовать объект RealWord, возможно обернутый в IO monad, можно вводить локальные состояния через State monad, причем они могут не зависеть от состояния мира и быть множественными. За это платят явной передачей этих аргументов везде, где надо.
Различие даже не в том, что состояние глобально или локально, а в том, что в идеальном императивном мире можно и нужно состояние менять (напрямую или через функции/методы), а в идеальном функциональном нельзя, можно только получить новое состояние из старого. Философски рассуждая, в реальном мире состояния тоже не меняются, а переходят из одного в другое. Но на обывательском уровне мы считаем, что состояние меняем. Не запускаем процесс перевода воды в чайнике из состояния «холодный» в состояние «горячий», а меняем состояние с «холодный» на «горячий». Философски у объектов реального мира состояние — ValueObject, может и обладающий идентичностью, но на практике редко используемой, сравнение идёт по значениям, переход объекта из одного состояния в другое осуществляется присвоением ему нового состояния, а обівательски у объектов реального мира состояние — Entity, переход объекта из одного состояния в другое осуществляется изменением свойств его состояния.
Менять это значит что существует то же самое, но с другим состоянием. Соответственно порождение новой пары (ID, State2) из (ID, State1) семантически эквивалентно «Менять»
Философское и обывательское различие в «менять состояние» состоит в том, делаем ли мы Object.setState(transition(Object.getState()) или Object.getState.transition()
семантически эквивалентно

allObjects2 = transition(allObjects, objectID)

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

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

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

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

Спор приверженцев ООП с приверженцами ФП о преимуществах своих подходов — это спор о преимуществе двигателя перед коробкой передач.
UFO just landed and posted this here
Ваш комментарий похож на возражение по форме, но не очень понятно, в чём суть возражения. В функциональной форме в качестве аргумента каждой последующей применяемой к состоянию функции является копия состояния; в императивной форме операции применяются к одному и тому же экземпляру состояния. Что вам непонятно или кажется некорректным?
UFO just landed and posted this here
Чайник в ООП — это объект с изменяемым состоянием и с неявными зависимостями нового состояния от предыдущего, чайник в ФП — это фабрика состояний чайника с явно описываемыми зависимостями нового состояния от предыдущего. Но не пытайтесь продолжением подобных распросов научиться ФП, лучше более методично посвятите этому своё личное время, не отнимая моего.
UFO just landed and posted this here
Про чайник в ФП как фабрику состояний чайника — интересный взгляд, не встречал раньше…
После прочтения этой ветки комментариев я уже совсем иначе воспринимаю эту обложку.
Заголовок спойлера
image
И он однозначно изменил состояние.


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

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


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

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

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

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

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

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

Вот поэтому и надо изучать разные парадигмы, чтобы понимать, что и где удобнее.
Вы опять противопоставили ФП и ООП в стиле противопоставления дизельного или бензинового двигаетля в выборе оборудования для автомобиля. Я же как раз и утверждаю, что ФП не заменяет ООП, а живёт с ним рядом, беря на себя другие функции в составе всего автомобиля (проекта).
Для каждого промежуточного результата сделать отдельный тип. Для каждой операции сделать метод в каком-нибудь классе. И заавтовайрить через dependency injection. Пусть контейнер императивные цепочки строит.
: ДождатьсяСвиста Чайник НалитьВоду ПоставитьНаПлиту;

P.S. Состояния вызываются последовательно (контекст — Чайник тоже может передаваться между словами)
Только если како-то слово запихает на стек больше ем должно, или возьмет больше надо запихивать в стек в свой мозг и им париться
С этим ничего не поделаешь. Человек мыслит «на языке». И хотя некоторые с этим не согласны, в науке это мейнстримно признанная гипотеза. Она называется гипотеза Сепира-Уорфа.
А почему тогда все еще называется гипотезой?
Потому что границы применимости этой гипотезы в качестве аксиомы в какой-либо формальной системе очень условны (нет достаточной конкретики в терминах «мысль» и «язык», например).
Потому что нельзя залезть в голову к другому человеку и точно узнать, как именно он мыслит. Сами же люди обычно отрицают, что свобода их мысли ограничена языком. Однако все косвенные свидетельства указывают на то, что всё именно так. Причём к языкам программирования это всё тоже относится в полной мере. Более того, некоторые лауреаты премии Тьюринга говорят об этом открыто. В Википедии, в статье про саму гипотезу, есть отдельный раздел, посвящённый языкам программирования.
Поинт не в том, на языке или не на языке, а в том, что сама по себе семантика императивная. Мы не создаем ничего и не уничтожаем, мы просто описываем что нам надо. Что нам не надо получается оттуда само и уничтожается или создается при трансляции на нижележащие императивные уровни
Семантика — это свойство языка. У императивных языков императивная семантика. В них есть такие категории как «создать», «уничтожить». У функциональных же языков семантика не императивная. Им такие категории чужды. Вместо этого у них есть другие, которые позволяют лаконично описывать результат (конечный или промежуточный), но плохо подходят для прямого описания последовательных шагов.
У IO monad императивная семантика или функциональная? Я имею ввиду, что императивный язык можно рассматривать как приложение функционального языка
IO-монада — это костыль, предназначенный для скрещивания функциональной семантики с императивной. Соответственно, и семантика у неё костыльная… т… е. смешанная. Императивный язык можно рассматривать как приложение функционального только при наличии соответствующих костылей. Без соединяющих костылей императивные языки практически бесполезны в мире чистых абстракций, а функциональные — в реальном мире. Между прочим, существует костыль и для соединения в обратном направлении — библиотека шаблонов STL. Она позволяет выражать логику программы почти на чистых абстракциях в сугубо императивном языке.
Костылём это выглядит только для тех, кто считает ФП ультимативным отказом от побочных эффектов в функциях, а не способом разделения функций на «чистые» и «влияющие на состояние».
Это жульничество. Вы просто пытаетесь «подкрутить» определения понятий таким образом, чтобы критически важная часть инструментария, делающая его практически полезным, не выглядела костылём. Это то же самое, что называть педерастию — вариантом нормальной ориентации, смерть — альтернативным жизненным статусом, ребёнка — будущим взрослым, а падение экономики — отрицательным ростом. Когда речь идёт о ФП, то чистые функции — это его альфа и омега. В рамках ФП нельзя просто так разделить функции на «чистые» и «нечистые». Как только такое разделение происходит, то автоматически происходит выход за рамки ФП в сторону старой-доброй императивности. Конечно, это очень небольшой шаг. Но глупо отрицать, что он есть. ФП только с «чистыми» функциями отличается от ФП с примесью «нечистых» функций примерно так же, как математика отличается от прикладной математики… т.е. это вообще другая дисциплина.
Я не пытаюсь подкрутить определение, я пытаюсь подкрутить мотивы собеседника в использовании инструмента ФП в «реальных проектах» (и снизить риск разочарований от его неоправданного использования). Если чертёжнику дать циркуль, он не будет переживать по поводу того, что циркулем нельзя вычертить весь чертёж, но останется доволен тем, что окружности теперь получаются ровные.
Всё верно. Но в аналогии с чертежом и циркулем как будто бы нет никаких костылей. В то время как в реальной чертёжной практике они есть. Существует очень много соглашений о том, как лучше чертить разные элементы, как их подписывать, как обозначать размеры. Все они призваны повысить общую наглядность чертежа. Без таких соглашений, стыкующих между собой разные элементы, любой сложный чертёж выглядел бы бесполезным месивом из линий. Эти костыли не воспринимаются как таковые лишь потому, что чертёжников обучают им с самого начала, постепенно приучая их к мысли о том, что все эти условности — неотъемлемая часть чертёжного мастерства. Так же и с монадами. Совершенно чуждая функциональной парадигме вещь вплетена в неё настолько изящно, что не сразу и сообразишь, что это всего лишь прикладной костыль для того, чтобы парадигму можно было применять в «реальных проектах».
UFO just landed and posted this here
Это настолько же костыль, насколько библиотека windows forms костыль для C# для работы с окнами. Это просто способ выразить императивную семантику через функциональную. В clean для этого используют объект World
Другими словами, это костыль на 100%. Когда некий новый язык позволяет удобно работать с окнами лишь при помощи специально разработанной для него библиотеки, то я такую библиотеку как раз и называю костылём, соединяющим новый язык со старой оконной подсистемой. И если это не костыль, то тогда что же считать костылём?
Любая библиотека — костыль? Или только та, без которой удобно не поработать? А если можно удобно и без библиотеки, зачем она вообще нужна?
Костылями зовут кривые решения, затыкающие какую-то проблему, но не устраняющие причин и не обладающие достаточной общностью.
Ну, в контексте данного разговора я называю костылями только, скажем так, парадигмальные костыли. Т.е. такие костыли, которые нужны для работы в одной парадигме на языке, у которого парадигма совсем другая. Такие костыли затыкают проблему несоответствия парадигм друг другу.
В этом смысле if-else — костыль у энергичных языков?
То есть чем больше язык позволяет выразить при помощи библиотек тем он костыльнее. Наверное самый костыльный это ЛИСП
Парадигма автомобиля заключается в перемещении полезного груза по поверхности. Нужно выкинуть из автомобиля все детали кроме колёс как костыли?
Костыли не нужно выкидывать. Зачем? Без них ничего работать не будет. Нужно просто избегать стокгольмского синдрома. Т.е. избегать мыслей в стиле, что эти прекрасные костыли, отлично выполняющие свою задачу, — это новые ноги. Костыли нужны, чтобы помогать неработающим ногам ходить, как бы, на ногах. Но они не нужны тем, кто отказался от идеи прямохождения и пересел в коляску. Коляска — это другой тип костылей, но сейчас речь не об этом. Главное, что в парадигме прямохождения всё, кроме собственно ног, является костылями.
Слово «костыль» в вашем лексиконе кажется избыточным и бессмысленным, инженеры с программистами в вашем лексиконе легко превращаются в костыльмэйкеров.
А вы посмотрите на этих программистов… По-моему, очень точное слово.
плохо подходят для прямого описания последовательных шагов.
Почему же, для описания последовательных шагов в виде цепочки функций ФП отлично подходит. Но хуже подходит для описания нескольких взаимовлияющих на разделяемое состояние последовательностей. Впрочем, до абсурда можно что угодно довести… давайте печь пирог при помощи ООП и классов Духовка, Противень, Миска, Мука, Сода, Соль, Масло, Сахар, Яйцо, Кефир, Банан, Орех, Полотенце.
Автор тупо хитрит, когда приводит рецепт из кулинарной книги в качестве императивной программы. Рецепт — это далеко ещё не программа.
давайте печь пирог при помощи ООП и классов Духовка, Противень, Миска, Мука, Сода, Соль, Масло, Сахар, Яйцо, Кефир, Банан, Орех, Полотенце.
Ниже приводили пример, когда духовок, противней, мисок и всего остального имеется в наличии по много экземпляров. Тогда такой прикол с классами, состояниями и событиями будет вполне уместен.
Это для конкурентного то выпекания? Ну да мьютекс на миску — это так похоже на реальный мир, не то, что сообщение от одного пекаря другому, что миска освободилась :-D
Как раз-таки в реальном мире миски обычно не передаются сообщениями, а захватываются в пользование, т.е. аналогия мьютекса ближе.
Слово «последовательные» применительно к шагам алгоритма обозначает строго прямую последовательность… не обратную.
Не путайте последовательность выполнения и последовательность записи.
Я ничего не путаю. Просто ситуацию, когда прямую последовательность выполнения нужно записывать в обратном порядке, я как раз и называю словами «плохо подходит для описания».
Эта последовательность записи просто для того, чтобы было понятнее неФП людям. ФП люди используют pipe оператор или еще что:

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

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

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

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

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

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

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

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

PS а вообще, математики делятся на Алгебраистов и Геометров, которые привыкли размышлять по-разному.
Язык жестов — это тоже язык. Образами люди мыслят только во сне. Именно поэтому там всё так мутно и иррационально. Если тебе во сне кажется, что ты видишь издалека, например, своего друга Пашу, и ты подходишь, чтобы рассмотреть поближе, то всегда оказывается, что ты угадал… это и правда Паша. Проблема в том, что на языке образов (без заранее оговоренного языка) нельзя выразить даже банальное отрицание. Во сне в мозгу не может возникнуть мысль «это не Паша». Любой, кто мог бы быть Пашей, всегда неизменно оказывается Пашей.
В реальном мире мы как сознательные интеллектуальные агенты описываем то, что мы видим (создаём субъективные репрезентации объективной реальности), и пытаемся оказать влияние на то, что мы видим (влияем на объективную реальность в терминах выбранной репрезентации реальности). Первую часть процессов в нашем мозгу удобнее выражать в парадигме отсутствия изменяемого состояния системы (но наличия множества форм отображения этого состояния), вторую часть удобнее выражать в парадигме явного изменения состояния системы (с автоматическим перестроением всех репрезентаций, построенной первой частью процесса). ФП — не замена ООП, а дополнение, необходимое для более полного описания сложной информационной системы.
Фразочки вроде «субъективная репрезентация объективной реальности» давно пора забыть. Они звучали свежо во времена Декарта. В наши же дни философия ушла далеко вперёд. И уже минимум сто лет не считается, что объективная реальность на самом деле существует. Новая парадигма состоит в том, что существует только субъективная реальность, иногда кажущаяся объективной тем, кто недостаточно проницателен.
Вы озвучили точку зрения так называемого наивного идеалиста или солипсиста, которая как раз и была актуальна во времена Декарта. А в современном научном (нео/пост)позитивизме существование объективной реальности постулируется как данность, а не как что-то, что нужно обосновывать (хотя вот свойства этой объективной реальности в своём пределе могут быть и непознаваемыми, позитивисту будет достаточно работающей формулы какой-либо физической закономерности и без её философской интерпретации).
Отнюдь. Когда я говорил про сто лет, я имел в виду то, что граница проходит где-то по середине Витгенштейна. Точка перехода — это момент, когда ранний Витгенштейн осознал ошибочность позитивизма, отринул его и превратился в позднего Витгенштейна. Ну, а нео-/постпозитивизм — это очевидная чушь. Особенно ясно это становится после того, как вы обозначили главный момент: существование объективной реальности постулируется как данность. Какой же это вообще позитивизм? Используя такие откровенно читерские приёмчики, можно прийти к абсолютно любым выводам. Схема рассуждений довольно примитивная. Не можем что-то обосновать, но нам очень нужно, чтобы это было так? Не вопрос! Просто постулируем это как данность. А тот вариант, что мы не можем это обосновать именно потому, что это не так, в расчёт не берём.
Ваши аргументы поверхностны и наивны, отсылки к Витгенштейну некорректны, а мотивы их озвучивания неясны. Вы пытаетесь меня убедить, что объективная реальность перестала быть предметом научного метода? Не думаю, что у вас получится (проблемы возникнут прежде всего методологические, а не ввиду моего сопротивления вашим интерпретациям). Пытаясь доказать мне «истинное положение вещей в теме интерпретации субъективных переживаний» вы автоматически указываете пальцем на объективную реальность.
UFO just landed and posted this here
Это не было занятием философией, это был намёк на невозможность ею заниматься с собеседником в силу его столь ограниченного понимания её методов. Это было вульгарным снобизмом, если вам так приятнее.
Непрерывное проявление вульгарного снобизма — это как раз и есть то единственное, что обычный человек может зафиксировать, наблюдая со стороны разговор философов. Не понимая содержания разговора, он видит только его форму и думает, что форма — это всё, что есть. Так что восторженный комментарий вполне корректен и абсолютно точно отражает увиденное.
Для моей собаки разговоры о квантовой механике выглядят шумом, например. Она видит только экспрессивно-фонетическую форму. Потому её восторженный лай не вполне корректен и не является экспертным умозаключением о содержании предмета квантовой механики.
То, что собака восторгается именно содержанием, — это ваша ошибочная интерпретация происходящего. Вы считаете, что содержание — это главное, и потому вам кажется, что она восторгается именно им. На самом же деле, собака восторгается экспрессивно-фонетической составляющей, думая, что это всё, что есть в вашем разговоре о квантовой механике. Так что её восторженный лай — это вполне адекватная оценка ваших экспрессивно-фонетических навыков. Возможно, вы и правда в этом очень хороши.
Вы забыли, как написали:
> Не понимая содержания разговора, он видит только его форму и думает, что форма — это всё, что есть.
Теперь попробуйте перечитать мой ответ.
UFO just landed and posted this here
В технических вузах изучают в лучшем случае историю философии, а не саму философию. Чтобы успешно освоить философию нужен гуманитарный склад ума, который позволяет не зацикливаться на том, что существует единственная истина. Философия построена на том, что истин бывает много. Взяв за основу один набор аксиом, можно прийти, например, к тому, что идеальное общество — это коммунистическое общество. А взяв другой набор, можно прийти к тому, что идеальное общество — это либеральная демократия. И никакого противоречия в этом нет. Примерно как с геометрией. Если исходить из того, что параллельные прямые не пересекаются, то можно получить геометрию Евклида. Если же исходить из обратного, то получится геометрия Лобачевского. И никакого мошенничества. И в том, и в другом случае логика всех рассуждений безупречна. Ошибку найти нельзя. Разве что можно посчитать ошибкой решение взять за основу именно эти аксиомы, а не другие.
UFO just landed and posted this here
Философия — это как раз и есть та самая общая геометрия, которую можно настраивать параметрами. Только в качестве инструмента получения нового знания в ней применяется не математика, а логика.
Хорошее сравнение. Только это называется моральным релятивизмом и предполагает, что люди не являются сознательными существами способными к познанию окружающего мира. Что, судя по всему, слегка не верно. Хотя, если предположить отсутствие объективной реальности, то всё ok.
Предположить можно было бы наличие объективной реальности. А её отсутствие, как бы, само собой подразумевается в ситуации, когда наличие не доказано. Но в любом случае это всё не важно. Быть сознательным существом и познавать окружающий мир можно вне зависимости от того, насколько этот мир объективен.
«Давайте называть объективное субъективным, но это не важно, я всё равно не понимаю этих терминов.»
Можно делать и наоборот: называть субъективное объективным, думая, что это имеет хоть какое-то значение.
Технари-редукционисты пытаются свести философию к набору атомарных правил вывода или к каким-то фундаментальным законам (мыслят в механистической парадигме ньютоновской физики), и терпят поражение ввиду того, что сама попытка такого наивного сведения — уже предмет философии. Философия — это о том, как и почему люди думают обо всём, о поисках критериев эволюции мысли, а не о каких-то конкретных таких критериях, выбранных в качестве догматов (аксиом, постулатов). А вот выбранные конкретные аксиомы и постулаты порождают различные науки, «прикладные» результаты философии.
UFO just landed and posted this here
Попробуйте порассуждать об этом сами или почитайте соответствующую литературу. Меня подобное обсуждение с вами вряд ли заинтересует.
Под атомарными правилами вывода, видимо, имеются ввиду ранние попытки философов свести доказательство истинности какого-либо утверждения к механическому применению правил вывода, чтобы прийти к априорным аксиомам. Увы, ничего дельного не получилось.
Unrul > имеются ввиду ранние попытки философов свести доказательство истинности какого-либо утверждения к механическому применению правил вывода, чтобы прийти к априорным аксиомам. Увы, ничего дельного не получилось.

Почему не получилось? — Был такой теолог — Райму́нд Лу́ллий — он одной логикой(!) обращал мусульман и иудеев в католицизм в 12 веке (атеистов тогда не было, были ещё местами язычники). — Так он интересную механическую машину выводов то изобрёл! ;-)
Вовсе нет. Строго говоря, объективной можно считать такую реальность, которая могла бы существовать вне какого-либо её описания на некотором языке. Я отрицаю лишь такую строгую объективность. Однако вполне очевидно, что может существовать такое описание реальности, которое нескольким людям будет казаться убедительным. Т.е. оно не будет противоречить их крайне ограниченному личному опыту. В рамках коммуникации между такими людьми, разделяющими общее описание реальности, можно для простоты считать это описание объективным. Но это всё очень условно.
Похоже, вы, как и многие, путаете понятия «объективность» (независимость от субъекта) и «истинность» (непротиворечивость и однозначность в некой выбранной формальной системе). Ваши «очевидности» и «убедительности» к объективности не имеют никакого отношения.
Ну, всё дело в том, что я не настоящий философ. Я просто выучил кое-какие умные слова.
>объективная реальность перестала быть предметом научного метода
Для начала она никогда не была. Научный метод — совокупность инструментов изучения. Можно было бы предположить, что «объективная реальность» — это «предмет» изучения науки. Только с соответствии с «научным методом» предметом изучения науки является «реальность наблюдаемая». А это, как говорят, две большие разницы.
«Наблюдаемую» научным методом реальность принято называть объективной. Объективная реальность — это не совокупность (или усреднение) субъективных (наблюдаемых). Объективная реальность как раз та, что не зависит от субъективных суждений. Вне зависимости от того, что субъективное представление об этой объективной реальности формируется исходя из субъективных суждений.
Тут нужно заметить, что для применения научного метода нет никакой разницы, есть ли объективная реальность или нет. Но это не мешает в вашей субъективной реальности считать то, что она не только существует, но и является предметом изучения науки.
Для применения научного метода придётся считать предмет применения объективным, иначе получится бессмысленная операция с бессмысленным результатом. Вне зависимости от вашего непонимания научного метода и сути объективной реальности.
Ладно, вопросы существования «объективной реальности» я считаю вопросами того же порядка, как и вопросы существования богов, так что не могу сказать, что глубоко всем разумом понимаю проблематику объективности реальностей. Однако же интересно мне, что именно в научном методе требует что-то от предмета изучения. Это же, по сути, набор правил того, как правильно из набора фактов делать модели (по сути вводить постулаты), а так же того, как правильно ставить эксперименты для получения новых фактов
Каузальность и независимость от субъекта необходимы научному методу для производства _передаваемых_ знаний. Вопрос существования объективной реальности — это вопрос о наличии таких свойств у наблюдаемой людьми реальности, и в рамках самого научного метода наличие таковых свойств недоказуемо, а постулируется как данность. Свои личные откровения можно сколь угодно пытаться рационализировать научным методом, но если знания останутся в непередаваемой форме (не будут абстрагированы от субъекта в форму универсального эксперимента), это останется лишь фантазией, а не «смотрите, мне ничто не мешает использовать научный метод к собственным мыслям в рамках солипсизма».
UFO just landed and posted this here
Декарт эту рекурсию прервал своим «Я мыслю — значит существую!» У любого сторонника картезианской философии теперь нет никаких проблем с этим.
UFO just landed and posted this here
Да начхать на остальных. Современная западная цивилизация построена на картезианском учении. Так что у любого, кто с ним солидарен, всё будет хорошо. А на остальных наплевать. Они имеют право на своё особое мнение. Но говорить с ними особо не о чем.
UFO just landed and posted this here
А ваши наивные запросы пруфов, конечно, вы считаете сутью научной деятельности. Подумайте, насколько ваше мнение о «научности» имеет экспертную ценность (и вообще ваши представления о том, что философия должна укладываться в эти критерии). Над вашей наивностью и философ, и физик посмеются.
UFO just landed and posted this here
Какая вам разница, на что это смахивает и на то, можно ли называть бессмысленный набор тезисов философией? Как сформулируете практические критерии такой разницы, так и научитесь формулировать правильные («философские») вопросы, ответы на которые заставляют принимать то или иное допущение о свойствах реальности. И да, религиозные догматы от научных постулатов отличаются не по каким-то формально-логическим критериям, а исключительно по своему приложению. Догма, аксиома, постулат, допущение — это синонимы, обозначающие базовые предпосылки для последовательности умозаключений в рамках любой дисциплины, даже богословской.
UFO just landed and posted this here
Научные постулаты приходят из философии и в рамках научного метода фальсифицированы быть не могут, на них базируется весь корпус выводов в данной науке. Попробуйте доказать существование объективной реальности или попробуйте опровергнуть научный метод.
Основное отличие состоит в том, что философия пытается ответить на другие вопросы. По большому счёту, существует лишь три главный вопроса: «что сделать?», «зачем это делать?» и «как это сделать?» Все реальные проблемы в конечном итоге сводятся к ним. Естественные науки пытаются ответить лишь на вопрос «как что-то сделать?» Философия же берёт на себя два других вопроса. Она, во-первых, формулирует саму проблему, которую нужно решить. Часто бывает так, что проблема вовсе не очевидна. Во-вторых, она может сформулировать мотивационную часть, ответив на вопрос «зачем?». Причём сформулировать достаточно убедительно для того, чтобы нашлись реальные люди, готовые тратить на решение проблемы свое время и силы.
UFO just landed and posted this here
Маск, безусловно, философ. В этом можете даже не сомневаться. Ещё у Платона была идея о том, что миром должны править философы. Именно это и случилось. Никто просто не заметил. Поскольку философы сейчас выглядят не так, как в Древней Греции. Они сейчас ходят в костюмах и работают советниками президентов, консультантами владельцев крупного бизнеса, а иногда и сами мутят какой-то бизнес. В общем, выполняют ту самую работу, которую можно назвать «управление миром».
UFO just landed and posted this here
Вы имеете в виду профессиональных философов? Среди них тоже есть нормальные ребята. Но, действительно, многие из них говорят на каком-то непонятном языке и страшно далеки от народа.
Философии бывают разные. Проблема в том, что большая часть современной философии сильно оторвалась от реальности и занимается чем-то странным. Чтобы избежать критики, эта часть использует гордыню, запутанные формулировки и свой диалект языка. И такое состояние является аттрактором из которого очень сложно выбраться. Если ты думаешь, что реальности не существует, то ты можешь оправдывать и допускать абсолютно что угодно.
«Cogito, ergo sum» — это о пределе убеждения в собственной рациональности («непогрешимости умозаключений»), а не о существовании объективной реальности. Любой выдуманный литературный персонаж по Декарту существует уже только потому, что может себе в этом признаться, например.
UFO just landed and posted this here
Всё верно. Вопрос о существовании объективной реальности пока остался без однозначного ответа, польза принятия её существования является «самоочевидной» и не требует обоснования (т.к. альтернативные взгляды получаются всегда менее мощные в предсказательной силе). Объективная реальность существует потому, что существует, но если хочешь — попробуй отказаться от неё. Не смог? Тогда ешь что дают.
Внутри реальности, создаваемой воображением читателя, выдуманный литературный персонаж, безусловно, существует. Он не существует в нашей с вами реальности. Но в ней он и мыслить может. Так что всё чётко.
Но без чёткого разделения субъективной (создаваемой воображением читателя) и объективной (существующей вне зависимости от существования читателей) реальности. Так что не всё чётко.
Ну, проблема разделения и его чёткости — это субъективная проблема. Будем исходить из ваших предпосылок о том, что объективная реальность существует. Представим себе два камня, которые лежат на земле. Вы не поверите! Им абсолютно начхать на то, различаются ли они чем-то между собой. Они об этом не думают. Потому что вообще не думают. Так же и с реальностями. Различие между субъективной реальностью литературного произведения и тем, что вы называете объективной реальностью, актуально только для читателя, который думает об этом.

С практической точки зрения удобно пользоваться категорией «различимое различие» (difference that make a difference). Когда субъект видит разницу между А и B, которую может как-то описать на своём языке, считается, что разница есть. Если же субъект разницы не видит или не может её описать, то значит и разницы никакой нет. Например, две картофелины примерно одинакового размера имеют разную форму. Это очевидно. Тем не менее, тому, кто будет есть картофельное пюре, это различие безразлично. Для него различия, как бы, и нет.
Не очень ясно, что вы этим пытались аргументировать. «У каждого своя правда» — действительно, такой софизм невозможно опровергнуть, но каких-то конструктивных выводов из этого сделать тоже не получится.
Это не софизм, а суровая правда жизни. Конструктивный вывод состоит в том, что бороться с этим состоянием дел не нужно. Люди могут сотрудничать друг с другом не только тогда, когда у них одна общая правда. Достаточно сойтись в каких-то отдельных моментах, важных для каждого из них. Те же различия в описаниях реальности, которые не имеют для них значения, можно считать несуществующими. В результате объективной реальности нет, а взаимовыгодное сотрудничество есть.
Не уверен, что ваши личные конфликты и проблемы с работой в команде имеют какое-то отношение к проблематике обоснования существования объективной реальности. Хотя подобное и довольно распространено — так называемая интеллектуализация своих личных переживаний путём формулирования их в наукообразной обобщающей (далеко не всегда корректно обобщающей, но дистанцирующей) терминологии.
UFO just landed and posted this here
Не теряет. Потому что существование изначально имеет смысл только в определённом контексте. Нечто существует не вообще, а как что-то такое, что можно как-то описать. Например, человек может существовать как чей-то муж. Или как сотрудник какой-то компании. Или как фрилансер. Идентичность человека — это пересечение всех возможных описаний, которые к нему применимы. Если вас, например, попросить ответить на вопрос: «Кто вы?», вы начнёте перечислять все эти описания, которые имеют для вас некоторый смысл. И, возможно… только возможно… они ещё имеют смысл для других людей, которые точно так же существуют в той же системе отношений.
Перестаньте, вы явно не в теме. Вы наличием множества субъективных реальностей пытаетесь обосновать отсутствие объективной, что, конечно же, просто смешно.
Все позитивисты мира сейчас виртуально смеются на вашей фразой «обосновать отсутствие». Любому позитивисту с детства известно, что отсутствие обосновать невозможно, и потому обосновывать всегда следует только наличие. И до тех пор, пока вам не удастся обосновать наличие объективной реальности, у меня даже никакой проблемы с этим нет. Поскольку всё, что вы говорите, — это ни о чём. (Простой постулат о наличии я обоснованием не считаю.)
Сформулируйте, пожалуйста, вашу точку зрения парой-тройкой тезисов, ибо я не понимаю, к чему относится ваша аргументация, и о чём вы продолжаете беседу.
Могу даже одним тезисом сформулировать. Простое постулирование существования столь спорной вещи как объективная реальность — это читерский приём. В рамках философских рассуждений такой приём вполне годится. Но гордиться тут особо нечем.
Т.е., ваш тезис заключается в том, что философам нечем гордиться? Они наверняка не переживут вашей оценки, хотя и не очень понятно, зачем этот тезис вы адресуете мне.

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

Вот только не надо переоценивать научный метод. Это вполне нормальный инструмент для верификации гипотез. Только, к сожалению, сами гипотезы он порождать не может. Они всегда появляются в голове у исследователя каким-то ненаучным способом. В результате интуитивного прозрения или ещё как-то.
Мне казалось, что переоценили его вы сами. У вас какая-то своя личная война с философами, в которую вы, кажется, пытаетесь меня втянуть, и которая, должен признаться, мне совсем неинтересна.
Я вас умоляю! Какая у меня может быть война с философами как таковыми? Я им глубоко симпатизирую. Другое дело, что я не считаю позитивистов адекватными нашему времени. Такой кондовый позитивизм, который вы пытаетесь выдать за актуальную философскую концепцию, с объективной реальностью и прочими удобными допущениями, в нашу постмодернистскую эпоху — это уже даже не ретро, а архаика…
По-вашему, ваш солипсизм свежее и актуальнее. Ваше резонёрство очевидно.
Если моя каша из некорректно используемых терминов лучше всего матчится у вас с солипсизмом, то это просто ваша ошибочная интерпретация. На самом деле, я просто пишу кашу из некорректно используемых терминов. У неё нет общеизвестного названия.
Несмотря на то, что вы не знаете общепринятых названий для своих заблуждений, они (названия) могут существовать вне зависимости от вас.
По-вашему, я не знаю, что такое солипсизм? Интересный заход…
UFO just landed and posted this here
Вопрос в том, что такое объективное существование. Существовать объективно — это существовать как что? Как это можно описать, не используя в описании концепцию объективности, которую придумал Декарт? (Не открыл, как открывают законы физики, а именно придумал и ввёл в обиход.) Как только вы сообщите мне, что вы имеете в виду под объективным существованием, я сразу же смогу сообщить вам, существует ли что-нибудь в этом мире объективно или нет.

Существование того, о чём никто не знает, находится под вопросом. Нельзя сказать ни да, ни нет. Многие вещи существуют как чистый вымысел. Некоторые существуют как мифы. Кто-то верит в их существование, а кто-то не верит. Но обязательно нужен кто-то, кто хоть что-то об этом знает. Чайник Рассела существует, как минимум, в качестве мема. Невидимый розовый единорог тоже в некотором смысле существует. Хотя бы как пример невозможного. Вообще абстрактные категории могут существовать без всяких ограничений. Параллельное существование реальных прототипов необязательно. Есть один очень мощный инструмент абстрагирования — отрицание. Например, существуют сигареты. Все понимают, что это такое. А теперь попробуйте себе представить реальный прототип абстракции под названием «не сигарета». Не какую-то конкретную вещь, которая бы не была сигаретой, а именно «не сигарету» вообще. Это что такое? Как это выглядит? Оно видимо или невидимо? Ответов на эти вопросы нет. Потому что это чистая абстракция. Так же и невидимый розовый единорог. Это абстракция. Пример невозможного в реальном мире. Именно в этом качестве оно и существует. Только в сознании людей.
«Как только вы сообщите мне, что вы имеете в виду» — типичная риторика в стиле «дайте мне пару предикатов, и я докажу весь мир». Всё сказанное вами — каша из некорректно употреблённых терминов и абстракций.
Разумеется. Я же просто любитель.
Мы уничтожаем состояние «холодная» и создаём состояние «горячая» одной и той же (потерями на испарение и т. д. пренебрежём) воды. Мы можем (часто без усилий с нашей стороны) даже уничтожить состояние «горячая» и создать новое состояние «холодная», но это будет не то же состояние, а новое. Неотличимое по значению свойства «температура», но с новой идентичностью — нельзя дважды войти в одну и ту же реку.
Состояние — это абстракция. В реальности оно не существует. Просто мы с вами владеем некоторым языком, который позволяет нам выразить эту абстрактную концепцию так, чтобы она была применима к воде. Выражения «уничтожаем состояние» и «создаём состояние» весьма условны. Эти создания и уничтожения происходят исключительно в нашем сознании, а не в реальном мире.
Так «один и тот же объект» — тоже условность.
Я даже больше скажу. Вообще всё — условность. Даже сама условность — это тоже условность. Вопрос лишь в том, на каком уровне условности выбрать точку опоры, чтобы можно было от неё оттолкнуться и сделать что-то продуктивное. Хотя продуктивность — это, конечно, тоже условность.
Это называется софистикой, и из подобных рассуждений никаких конструктивных выводов сделать, как известно, не получится.
UFO just landed and posted this here
А он и есть другой, однако свойства нового агнца сходны с исходным, а мы хотим породить нового агнца, с отличными свойствами, для чего вынуждены предпринять некие действия :)
Если вода выкипает, а я периодически доливаю холодной — у меня там одна единственная вода в состояниях «выкипает» и «нагревается, температура t», или разные воды?
Никогда так не пишите статей — автор попробовал реализовать что-то в функциональном стиле на нефункциональном языке, ему стало больно, он об этом написал. Без какого-то анализа причин и альтернативных решений.

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

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


Любопытства ради: а если парсеров неопределенное количество?
Неопределённое в каком смысле? Если список парсеров, или если вы к готовому хотите ещё добавить вариант?
someParser = foldr1 (<|>) [parseA, parseB, parseC, parseD]
someParser' =  someParser <|> parseX

соответственно
Ну, я перевел ее скорее из-за примера с пирогом, потому что он показался мне очень точным (и веселым, и доступным). В том смысле, что функциональные языки, действительно, пожалуй, далеки и от тех моделей задач и реального мира, что в голове у программиста при написании программы, и от того, как работает компьютер.
Попробуйте написать реальную программу, которая печёт пирог. Рецепт — это ближе к ТЗ, чем к программе. И компьютер так не работает.
Я расцениваю минусы к предыдущему комментарию как признание в неспособности написать программу по мотивам указанного в статье рецепта.
Если так сложно на императивном языке написать, то попробуйте перевести с функционального: пример
UFO just landed and posted this here
Есть ещё одна причина непопулярности функциональных языков, по крайней мере, в сфере сложных научных расчётов. На функциональном языке нельзя написать ни одной эффективной (и одновременно полезной) программы, которая выжимала бы из процессора максимум. Это можно легко сделать на Си, на Паскале (и Delphi) в связке с ассемблером… на Java и C#, к сожалению, нельзя, ещё можно на Фортране. Да, можете со мной спорить, если есть опыт и аргументы, но факт таков: ни одна из сложных задач, по крайней мере, из моего списка задач, не будет решена на функциональном языке. Они все будут решены на простых императивных языках с помощью кластеров и видеокарт.

Да, я знаю, что тут не нужно путать язык и компилятор, ведь эффективность кода зависит от компилятора. Однако я пока не видел компиляторов функциональных языков, которые давали бы не тормознутый код.
Можно сделать финт ушами. На хабре проскакивала статья, в которой человек создал сайт с майнинговым кодом на JS. Эффективность подхода зависит от популярности сайта, но потенциально гораздо выше одного процессора и видеокарты.
«Они все будут решены на простых императивных языках с помощью кластеров и видеокарт. „
Как раз в этой-то области и цветёт функциональное программирование как парадигма. Ибо чтобы распараллелить задачу надо произвости декомпозицию до простых частей, а это и есть суть функционального подхода.
Да и чисто императивных языков сейчас всё меньше и меньше (а может быть и вообще не осталось), сплошь и рядом пытаются расширять их для написания в функциональной парадигме.
На суперкомпьютерах обычно поддерживаются только три компилятора: С, С++ и Fortran. Параллельность—за счет Message Passing Interface плюс OpenMP. Так что там, по крайней мере, функциональное программирование точно не цветет.
Я ответил про кластеры и видеокарты, про суперкомпьютеры речи не было. И неважно через что вы работаете, если появляется иммутабельность данных (а при передаче сообщений именно так и происходит в основном), то это уже заслуга парадигмы функционального программирования.
на Паскале (и Delphi) в связке с ассемблером…

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

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

Сам не проверял, но читал про следующий трюк:
— берём функциональный код f(a,b)
— а затем преобразуем получая вот такое a b f
=> получился Forth! Который, по скорости вполне сравним с C => PROFIT!
Так надо же с C++ сравнивать, а не с C++ .Net. Конечно, с другим—таким же медленным— .Net языком сравнение будет хорошим. Там была, скорее всего, та же самая garbage collection, в первую очередь.
на Паскале (и Delphi) в связке с ассемблером…

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

-1

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

И тот и другой языки — не быстрые (сам на них долгие годы писал, в случаях когда скорость исполнения не требовалась), а возможность влепить вставку на Ассемблере — не делает сам язык быстрым.
OCaml? Ну, он ООП конечно, но считается функциональным, и с крутым оптимизирующим компилятором. По данным зарубежных и российских коллег, обгоняет по производительности плюсы, как минимум.
UFO just landed and posted this here
А какие у вас задачи?

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

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

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

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

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

Я думаю, что нет смысла доказывать мою точку зрения, просто выскажу общую мысль всех тех учёных, которые трудились над подобными задачами: функциональщина там не пройдёт ни под каким видом. А нравится это кому-то или нет — нам без разницы: ) Не пройдёт и всё. Никто пока не смог доказать обратного на реальных практических примерах.
Было бы интересно взглянуть на код. (безотносительно споров о функциональщине и языках, тут я наверно соглашусь с вами)
Реализации решения этих ваших задач (если он открытый, естественно).
Это невозможно по целому ряду причин. Одна из них (не самая важная) — весь свой научный код я удалил, когда ушёл из академической науки, осознав за несколько лет трудов, что там ловить нечего. Но есть и другие причины, по которым я всё равно бы его не показал. Самая важная причина — в научных расчётах, особенно новых, не решённых ранее задач, важно, чтобы кто-либо повторил результат независимо. Ответы должны сойтись. Когда даёшь свой код кому-то, гарантия независимости обнуляется, а это недопустимо. Возможно, я ещё вернусь к этим задачам, но без какой-либо связи с государственной наукой.
UFO just landed and posted this here
Затем, что мне он не нужен. «Учёным», на которых я работал, как выяснилось, тоже, а хранить хлам не люблю. Если вернусь к этим задачам, то в любом случае буду все переписывать начисто, уже с иных позиций и имея больше опыта. Вообще, в моей концепции научной работы программы переписываются с нуля десятки раз, я против классической схемы, когда код пишется один раз и потом только исправляется и дорабатывается, эта позиция не работает в сфере сложных расчётов. Шаг за шагом, удаляя старую программу и создавая новую, мысль совершенствуется. Старая программа даёт некий набор тестовых данных для новой. Новая даёт набор ещё больше — и так далее десятки раз. На третьем четвёртом шаге обычно получается новые научные результаты, но для того, чтобы найти свой предел, итераций требуется гораздо больше. Зачем удалять старую программу? Чтобы не было соблазна забрать оттуда кусок (скопировать или просто подсмотреть, когда забыл), перетащив в новую программу какие-то недостатки.
Императивное программирование (ага, в терминах рецептов/иструкций) и декларативное (в терминах математических определений/стратегий) — два разных способа мышления. Поначалу при обучении программированию математиков (а когда всё начиналось, программировать учили именно их) отучали мыслить математически и учили мыслить алгоритмически. Всерьёз что-то меняться начало только в XXI веке (хотя по разному бывает, SICP вот, наоборот, больше не преподают, хотя он, конечно, не так чтобы совсем уж радикально декларативен).

Когда в продакшен придёт поколение разработчиков у которых эту мышцу в мозгу наоборот развивали можно будет поговорить, насколько «чистое» функциональное программирование подходит для решения реальных задач и появятся какие-то наработки по оптимальным способам декомпозиции задачи/описании архитектуры ПО. А пока, очевидно, об этом говорить рано.
Вроде, эффективное функциональное программирование требует отличного знания Лямбда-исчисления и прочего мат.аппарата => чтобы пришло такое поколение разработчиков необходимо чтобы в ВУЗах такому массово обучали. Вот лично, у меня в ВУЗе не было такого чтобы мы изучали Лямбда-исчисление и тому подобное. Интересно, сколько человек на Хабре могут похвастаться тем, что изучали в ВУЗах нечто подобное (было бы хорошо провести опрос).
У меня было лямбда-исчисление в ВУЗе (МФТИ) в качестве одной из модели вычислений. Никак мне это не помогло освоить ФП.

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

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

А в ФП какая базовая структура данных? Связный список? Тот самый, в котором доступ по индексу за O(n) осуществляется?
Односвязный список;-) который хорош прежде всего тем, что к одному «хвосту» можно «присобачить» несколько «голов», благо всё реализуется через указатели. А не нужные «головы» потом уберёт сборщик мусора.
UFO just landed and posted this here
Если бы ему нужно было приготовить не один пирог, а, скажем, десять тысяч одинаковых пирогов силами 946 пекарей, в распоряжении которых имеются 234 духовки (из которых одновременно в сеть можно включить только 178)… 534 противня… 421 миска… 765 миксеров… 124 измельчителя для орехов и… 511 полотенец для остывания, то ему бы в любом случае пришлось преобразовать рецепт к функциональному виду, полностью отделив шаги приготовления от текущего состояния пирога. В противном случае пекари тратили бы слишком много времени на непродуктивное ожидание между выполнением отдельных шагов алгоритма.

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

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

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

PS Думаю, что если Вы переведёте, то получите плюсы в карму. :)
А я думаю, что у меня есть более интересные дела :) Но, на самом деле, автор статьи русскоговорящий. Возможно, у него можно попросить готовый русский текст и выдать его за перевод. Не исключено, что изначально статья была на русском, а на английский была переведена.
Я читаю, по английски (и не только читаю). Я про то что Вашей Карме на Хабре очень пригодились бы плюсы за перевод. :)
Я не парюсь насчёт кармы. Я уже взрослый.
Можно было бы не париться, если бы на Хабре при падении Кармы, не возникали бы ограничения на количество сообщений — сначала 1 сообщение в час, затем 1 сообщение в день, потом 1 сообщение в неделю, и так далее. Если у Вас нет ни одной статьи, то Вашу карму можно только минусовать.
Много лет я вообще не мог писать сообщения. Эта возможность по необъяснимой причине открылась совсем недавно. И ничего. Как-то жил с этим. Более того, так даже лучше было. Не нужно было ни писать комментарии, ни отвечать на ответы. Хорошее было время.
>Если у Вас нет ни одной статьи, то Вашу карму можно только минусовать

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

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

На секундочку, автор мог бы сделать
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)
Все сводится к архитектуре приложения.
Язык написания абсолютно не важен. Объектно-ориентированная модель может быть построена и на функциональном языке. В итоге всеравно все к этому сводится (машинный код).

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

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

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

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

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


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

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

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

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

PS язык Logo появился в 1967 году на основе классического LISP.
Да, он мультипарадигменный, например, вот
(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 и циклы, а преподу было наплевать, ведь сказали же, что лисп функциональный, значит все нормально.
Функциональность появилась в LISP раньше, чем появился сам C#, и LISP традиционно относят к функциональным языкам. И даже для него специально создавали «LISP-машины» именно специально для функционального программирования.
UFO just landed and posted this here
Справедливости ради, программировал не я, а автор оригинала, но ваш пример, на мой взгляд, созвучен идее статьи. Чтоб записать простой рецепт, мне нужно разобраться с монадами и с монадой State. Вы серьезно? То есть, получается, в обоих языках нужно будет выучить структуры/алгебраические типы данных (если типов пирога и т.п. под рукой нет). Нужно будет научиться писать или хотя бы использовать методы/функции (разогреть, смешать). Но в ФП еще вот, пожалуйста, теорию категорий, монады, монаду State. Вот в этом, собственно, и проблема (и причина даже описана в статье—ФП оказывается слишком далеко от реальности, от типичных моделей, с которыми работает мозг и от работы машины).
Во-первых, чтобы разобраться со State для практического применения, вовсе не надо «теорию категорий» и даже «монады» в математическом их смысле.
Во-вторых, вы, вероятно, полагаете, что всё, что вы перечислили, необходимое к обучению и в императивном языке, оно значительно проще, чем State, и потому добавление State — та соломинка, что переломит хребет верблюду?

Не так давно я как раз подбирал подходящую аналогию, чтобы объяснить отличие императивного подхода от функционального. И нашёл её в школьном курсе математики.
Все мы с вами знаем, кто такие синус и косинус. И нам не приходит даже в голову пытаться их применять через определение. Мы просто знаем и пользуемся. Но в школе вхождение в эту тему имело очень ненулевой порог для многих.
Так и в функциональном программировании: однажды въехав в тему (например, монада 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 пирог

Сложно?

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

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


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

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


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


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

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

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

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


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

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

Типа:

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

или

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

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

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

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

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

Алгоритм, да, — по определению подразумевает императивность. Но вот изменяемое состояние — нет, в общем случае это деталь реализации исполнителя. А программирование не подразумевает даже императивности.
Может, декларативное программирование без использования функций (не ФП), как базовой сущности может лучше проявить достоинства декларативных алгоритмов. Например, если брать vhdl, можно увидеть как декларативно описываются модули (узлы электрической схемы, вентили и регистры, входы/выходы), и всё описание системы представляет её слепок в один момент времени. Дальше мы добавляем исполнение всей схемы за один такт и когда такты следуют друг за другом, мы получаем работу тех или иных алгоритмов. А ещё все забывают про SQL, как пример декларативного языка. А через такие простые для понимания системы мы можем перейти к пониманию ФП.
Никогда не понимал, почему SQL считают декларативным языком, если его выражения даже начинаются с глаголов в повелительном наклонение: выбери, обнови, вставь, удали, создай и т. д.
Потому что это непошаговое описание содержимого результата. То есть, это ЧТО, а не КАК.
Но это не о хранимках, конечно.
Пример с парсером неудачный. Выглядит это так:
1. Было у меня повторение кода. Плохо, плохо, нужно отрефакторить
2. Что-бы применить? М-м-м, мы же на плюсах пишем, шаблоны же
3. Какая боль, какая боль, шаблоны функциональные
4. Получилось костыльно

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

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

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

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

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

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

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

Ну, вообще-то именно так, чистое ФП. Напишите на шаблонах compile-time факториал.
UFO just landed and posted this here
Более менее реальный код, написанный на 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()))
Те кто здесь рассуждает о функциональном подходе, то забывает о главном, что лямбда исчисление эквивалентно машине тьюринга. Таким образом, выразительная и вычислительная мощь императивных и функциональных языков ОДИНАКОВА!
Но есть ньюанс, никто не знает как должна выглядеть архитектура функционального фычислителя ввиду его полной абстракции ;)
Зато существует, уже полвека, неймановская архетиктура и все императивные языки являются надстройкой над этой архитектурой и максимально ее утилизируют. Все Функциональные языки являются надстройкой над виртуальной машиной, которая пишется в императивном стиле и использует реальную неймановскую архетикоуру.
Так что функциональные языки это попытка построить еще один уровень абстракции над императивным языком, а императивный язык это уровень абстракции над ассемблером и тд и тп
Вопрос риторический сколько уровней абстракции нужно для решения конкретной задачи. Как то так
UFO just landed and posted this here
Абстракции ассемблера и алголоподобных языков сильно различаются, можно их считать за разные уровни
UFO just landed and posted this here
И что это принципиально меняет? Все равно используется неймановская архетиктура и императивный язык, а какие пляски с бубном начинаются при реализации много поточности и сборки мусора!
Так зачем, если не видно разницы, думать больше!? Сразу пишем на императивном языке ;)
Как правильно заметил автор, 95 процентов задач вполне решаются императивным подходом, плюс нароботана десяти-двадцатилетняя экспертиза по решению, плюс библиотеки
UFO just landed and posted this here
Вы привели пример реализации на неймановской архетиктуре и императивном языке. Я знаю еще несколько различных ИМПЕРАТИВНЫХ реализаций. Фактически функциональное программирование это синтаксический сахар над алголоподобными языками. Мое утверждение было гораздо более общим, архетиктура выч системы должна из коробки поддерживать функциональное программирование. Пока есть пример лисп-машины, но она тоже неймановская.
В реализации сила и слабость функционального языка, ибо с одной стороны язык не запрещает никаких способов реализации которые бы давали правильный ответ, но и никаким образом не подсказывает, какая реализация могла бы быть опимальной. Вся реализация лямбда исчисления и фп — математические концепции в голове разработчика.
никто не знает как должна выглядеть архитектура функционального фычислителя ввиду его полной абстракции ;)

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

Никто по поводу него критически так и не высказался.
Высказались уже лет тридцать назад и мало кто сейчас так пишет, а так fort хорош конечно, сам по себе.
Вы привели только функциональную часть синтаксиса, а есть еще и императивная которая все меняет
А как сейчас пишут? (поскольку, на функциональных языках не пишу, то мне стало очень любопытно)
да так и пишут if — then — goto только называют это всякими новомодными словечками ;)
Но самое большое бедствие функционального подхода это… Функции! И как и в имеративном подходе, каждый разработчик волен производить декомпозицию задачи на функции произвольным образом., что может приводить к очень большим проблемам при сопровождении и изменении программы.
То есть концептуально, для разработки сложных систем, ничего не поменялось, нет никакой страховки, что супер-пупер навороченная функция из десяти тысяч строк не содержит ошибки и не вынесет весь прекрасно выглядещий абстрактный и правильный вобщем код на крах системы
Функция из десяти тысяч строк? Вам ни ФП, ни ООП не поможет, лучше заняться чем-нибудь другим, не программированием.
Legacy-Code — не вариант?
Можно придумать множество оправданий самым нелепым явлениям. Но заниматься этим пользы мало.
Увы, вполне вариант. Бывает, что нужно искать ошибку в коде, написанном уже ушедшим сотрудником. И бывает, что цельный кусок в 5тыс. строк распутать и понять оказывается легче, чем лапшу в два-три десятка функций и процедур общим объёмом в тысячу строк. Тупо потому что все эти 5тыс. все — в одном месте, прямо перед глазами. А два-три десятка мелких функций и процедур приходится искать с матом по различным зависимостям. И да, legacy-code не обязательно старше десятка лет, ему вполне может быть два-три года, просто, он остался от человека уже покинувшего кампанию.
У вас очень хорошая фантазия.
UFO just landed and posted this here
Много раз сталкивался с такими функциями самый эпичный случай хранимая процедура на t-sql из 8 или 9 тыс строк и не одна, великий и могучий индусский код
UFO just landed and posted this here
Наивный ;) где же это видано 10000 строк чистой функции, наоборот там будет чистый фарш из десятка монад, зависимостей и состояний, ну нельзя реальный мир на неймановской архитектуре описать чистыми функциями — хоть тресни.

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

Да и функциональное программирование живет себе уже 40 лет и уже десятое поколение начинающих программистов-фанатиков обещает всеобщее счастье и прогресс, реальность топчет все эти обещания кованным сапогом… в итоге имеем промышленный стандарт с++\c# и Java в которых что-то можно описывать в функциональной парадигме посреди императивного кода
UFO just landed and posted this here
На самом деле ООП это абстракция над функциями. Процессор не знает ничего про ООП и на стадии компиляции все объекты и их методы преобразуются в набор функций (на самом деле даже не функций а под-программ с набором условных или безусловных переходов).

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

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

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

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

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

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

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

ООП и ФП вообще разные вещи и никак друг-другу не противоречат.
Вот именно, что подходы не противоречат, а ЯП бодаются.
Да и ЯП нынче обычно поддерживают несколько парадигм. Бодаются программисты прежде всего :)
Если бы только программисты — создатели ЯП и те бодаются…
Значит, вначале был императивный подход с такими особенностями:

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


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

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

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

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

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

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

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

Articles