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

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

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

const waypoint = new Waypoint({
  element: document.getElementById('thing'),
  handler: () => console.log('You have scrolled to a thing')
})

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

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

Функциональное против Объектно-ориентированного


Начнём с небольшого аргумента, в сторону функционального программирования

image

(игра слов: fun — весело, poop — дерьмо)

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

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

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

  • Объектно-ориентированное программирование легко понять, потому что оно имитирует то, как люди думают об окружающем мире.
  • Функциональное программирование более трудное для изучения и требует небольшого переустройства мозга, потому что заставляет тебя думать иначе, чем в повседневной жизни.

Так почему же кто-то должен перестраивать своё мышление, когда ООП интуитивно понятное и знакомое? Только ради хвастовства? Или может некоторые люди хотят сделать их работу (и их команды) тяжелее, введя много математики? Нет. ФП может быть сложным в изучении, но преимущества того стоят.

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

Как закрыть дверь


Представьте, что вы создаёте мир, и создаёте новую функцию — двери. Они могут быть закрыты или открыты, ограничивают или открывают доступ в комнату. Круто! Но нам нужен код, чтобы они работали, во-первых, функциональным образом:

// Чтобы не менять данные, первым аргументом для Object.assign будет пустой объект
// смотри: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
const open = obj => Object.assign({}, obj, {locked: false}) 

// теперь, давай сделаем дверь:
const myDoor = {
  color: 'red',
  locked: true,
}

// myDoor не будет видоизменяться (если мы будем придерживаться функционального подхода),
// поэтому мы получим новый объект "дверь", если мы откроем её
const myDoorOpened = open(myDoor)

И теперь, объектно-ориентированный:

// начнём с объекта дверь:
class Door {
  constructor(color, locked) {
    this.color = color
    this.locked = locked
  }
  open() {
    this.locked = false
  }
}

// создадим новый объект "дверь"
const myDoor = new Door('red', true)

myDoor.locked // -> true
myDoor.open()
myDoor.locked // -> false

Итак, какие преимущества ФП мы можем здесь увидеть?

  • Переиспользование. В функциональной версии, функция open может может открыть всё, что имеет boolean locked свойство. В будущем, мы можем сделать сундук и использовать ту же функцию, чтобы открыть его. ФП позволяет писать небольшие, чистые функции, которые следуют Unix концепции: Do One Thing and Do It Well.
  • Неизменность. По мере роста кода, будет всё сложнее отслеживать объект myDoor в ОО версии (он уже был открыт на строке х?). В долгосрочной перспективе просто безопаснее использовать неизменные структуры данных, которые ФП поощряет.
  • Данные. В версии с ФП, myDoor это чистые данные, которые могут быть импортированы из файла JSON или получены из REST API. В версии с ООП, myDoor это объкт, который хранит данные, а так же методы, для управления этими данными.
  • Краткость. По мере роста кода, его сложнее поддерживать, а функциональный код более краток.

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

Например в языке Elm, компилятор предупредит тебя, если ты забудешь о case в операторе switch. Функциональный стиль передаёт больше информации о цели программиста, поэтому среда разработки может работать с вами, почти как напарник программист.

Функциональное программирование в фронтенд разработке


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

  • TypeScript и Flow обеспечивают строгую типизацию в JavaScript. TypeScript является надстройкой над JS, в то время как Flow это предупреждающая система, которая предупредит вас, если, например, число передается там, где должна быть строка.
  • Ramda это “практическая функциональная библиотека для программистов JavaScript.“?—?в общем мощный функциональный инструмент. Как lodash или underscore, но с ФП.
  • Redux это библиотека для контроля состояний, которая включает в себя ФП с идеей чистых функций в своём ядре.
  • Elm, ClojureScript, PureScript — функциональные языки, которые компилируются в JavaScript. Кривая обучения гораздо круче, чем в вышеупомянутых проектах.

Что дальше?


Если ты хочешь окунуться в функциональное программирование, я бы посоветовал следующее:

  1. Исчерпывающее, но очень доступное введение в ФП
  2. Руководство по функциональному программированию профессора Фрисби (бесплатная электронная книга)
  3. Функциональный язык программирования — эти загадочные термины

И если ты из мира JavaScript:

  1. Мысли в Ramda?— введение в Ramda
  2. Потрясающее ФП JS?—?функционально-ориентированные ресурсы для JS
  3. Что такое функциональное программирование Эрика Эллиота

Спасибо за чтение!

Если вы нашли какие то опечатки или есть предложения по переводу — прошу писать в личные сообщения.
Поделиться с друзьями
-->

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


  1. azat-io
    19.03.2017 17:56
    -6

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


    1. vasya-ves
      19.03.2017 19:03
      -2

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


    1. Semigradsky
      19.03.2017 21:34
      +1

      Рыба во море?


      1. kanstantsin
        19.03.2017 21:38
        +1

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


        1. viktorkorsun
          20.03.2017 12:16
          +3

          обход дерева во глубину? :)


          1. vintage
            20.03.2017 14:42
            +2

            В данном случае это наречие "Обход вглубину". А вот тут уже существительное с предлогом: "во глубине веков".


            1. viktorkorsun
              20.03.2017 23:55

              Тоже так думал, но в подавляющем большинстве источников по computer science на русском пишется раздельно. Думаю, в заголовке статьи играет роль факт, что следующий звук, [ф], является глухой парой звука [в], и интуитивно хочется их разделить заменой предлога на «во». В других случаях, например, «в глубину», «в примечании», «в предложении» такого желания не возникает. Жалко, у меня нет лингвистического образования, интересный вопрос. Прошу прощения за флейм.


              1. vintage
                21.03.2017 08:24

                После изучения Японского после каждой согласной хочется влепить гласную :-) "во голубину", "во поримечании"


    1. TheShock
      19.03.2017 21:35
      -1

      А почему ваша статья «Используем возможности CSS4 уже сегодня с cssnext» не называется «Используем возможности CSS4 уже сегодня со cssnext»?


      1. kurt_live
        20.03.2017 10:05
        +1

        <зануда> c CиЭсЭс… </зануда> ну и подставь теперь сюда со


  1. seryh
    19.03.2017 19:46
    +4

    После позитивного опыта с Clojure, у меня сложилось мнение, что
    писать на JavaScript в функциональном стиле, это лучший способ
    испортить себе все впечатление об ФП. Как ни крути но JS это ООП язык
    и функциональный стиль привнесен туда через сомнительного удобства
    костыли. Кто хочет использовать функциональный подход, который сделает
    разработку фронтенд приложений приятным времяпровождением, смотрите — Elm, ClojureScript, PureScript.


    1. Minoru
      21.03.2017 00:20

      А по каким критериям вы определяете ООП язык и функциональный?


      1. seryh
        21.03.2017 05:28

        По наличию соответствующей записи о языке в wikipedia.


  1. lair
    19.03.2017 20:19
    +16

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

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


    Так что — в рамках метафоры — задача-то на самом деле не решена. М?


    В функциональной версии, функция open может может открыть всё, что имеет boolean locked свойство.

    Это, простите, преимущество функционального подхода? В ООП все, что имеет контракт Openable, имеет метод Open, который делает все то же самое, и свойство IsLocked, который отвечает на вопрос, заперт ли объект — и при этом это свойство нельзя назначить снаружи.


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


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


    ФП позволяет писать небольшие, чистые функции, которые следуют Unix концепции: Do One Thing and Do It Well.

    А ООП не позволяет? SRP, не?


    В версии с ФП, myDoor это чистые данные, которые могут быть импортированы из файла JSON или получены из REST API.

    … и изменены любым образом без контроля со стороны бизнес-логики, ага. Это же "просто данные".


    Например в языке Elm, компилятор предупредит тебя, если ты забудешь о case в операторе switch.

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


    Функциональный стиль передаёт больше информации о цели программиста,

    А на чем основано это громкое утверждение?


    При этом, хочу заметить, что я ничего не имею против ФП, я сам с удовольствием его использую. Но вот применяемые в статье аргументы… гм.


    1. vasya-ves
      19.03.2017 20:37

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


      1. lair
        19.03.2017 20:39
        +10

        Но для новичка в ФП, они достаточно наглядно показывают его в действии.

        … показывают неправильно и вызывают вопросы.


        Единственно предназначение этой статьи, показать что функциональное программирование можно использовать в JavaScrip, заинтересовать.

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


        К сожалению, ответить на ваши вопросы я не могу, потому что не я автор статьи и с ФП только начал своё знакомство.

        Вот за это я и не люблю переводы на хабре.


      1. DeadKnight
        19.03.2017 21:59
        +7

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

        Но самое главное. Все эти попытки противопоставления ФП и ООП, они подобны потивопоставлению картошки и апельсин. Зачем они?


    1. HKA
      24.03.2017 11:59

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

      Напомнило анекдот про пепельницу в «Мерседесе». Функциональный подход, когда это еще не было мейнстримом )


  1. vasya-ves
    19.03.2017 20:50

    … показывают неправильно и вызывают вопросы.

    В конкретном примере нет никаких ошибок.
    Вызывают вопросы? Прекрасно, есть стимул продолжить изучение!
    А в коде в вашем посте не видно никакого преимущества от использования ФП.

    Все преимущества так же расписаны.


    1. TheShock
      19.03.2017 21:00
      +1

      Вызывают вопросы? Прекрасно, есть стимул продолжить изучение!

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


    1. lair
      19.03.2017 21:13
      +3

      В конкретном примере нет никаких ошибок.

      Есть: задача не решена.


      Все преимущества так же расписаны.

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


  1. vintage
    19.03.2017 21:10
    +7

    JavaScript обычно используется в ООП, но ничто не мешает нам использовать его в функциональном программировании.

    Мешает отсутствие гарантий и соответствующих оптимизаций.


    Краткость. По мере роста кода, его сложнее поддерживать, а функциональный код более краток.

    const open = obj => obj.locked = false
    
    const myDoor = {
      color: 'red',
      locked: true,
    }
    
    open(myDoor)

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


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

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


    Неизменность. По мере роста кода, будет всё сложнее отслеживать объект myDoor в ОО версии (он уже был открыт на строке х?)

    Вешаем "акцессор" и можем в нём хоть брейкпоинт ставить, хоть логгер вызывать.


    Данные. В версии с ФП, myDoor это чистые данные, которые могут быть импортированы из файла JSON или получены из REST API.

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


    1. areht
      19.03.2017 21:28

      > использует инкапсуляцию для обеспечения полиморфизма.

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


      1. vintage
        19.03.2017 21:32

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


    1. DeadKnight
      19.03.2017 22:13
      +5

      Кстати, почему решили, что locked обязано быть boolean? А если это 3-х позиционный замок: открыто, закрыто, открыто но на цепочке? И вот, весь показанный бонус от ФП пошел лесом. В то время как в солучае ООП мы проблем не получили.


    1. wheercool
      21.03.2017 11:06

      Состояние объекта вы так же легко можете десериализовать

      А состояние всей системы? :)


      1. vintage
        21.03.2017 12:05

        Это ещё проще — обычный дамп памяти.


        1. lair
          21.03.2017 12:11

          Обычный дамп памяти — это сериализация. А вот обратно...


          1. vintage
            21.03.2017 13:41

            А обратно просто загружаем образ и продолжаем работать. SmallTalk так работает.


  1. AndreyRubankov
    19.03.2017 21:36
    +5

    Еще одна статья, которая имеет лишь громкий заголовок, но при этом не показывает ни достоинства ФП, ни недостатков ООП. Зачем?

    Каждая статья из серии «ФП лучше ООП», всегда выглядит одинаково:
    — «вот есть неизменяемость!» (которая дает преимущество ТОЛЬКО в многопоточной среде, но при этом имеет огромный ряд недостатков; лепить его везде — глупо! этим инструментом нужно пользоваться осмысленно!),
    — «вот есть чистые функции!» (это хорошо, но без побочных эффектов невозможно построить ни одно приложение),
    — «а ООП — это вообще фу-фу-фу!»

    На самом деле, чисто ООП — не самая лучшая парадигма, но и чисто ФП — тоже!
    Идеал — золотая середина между ООП и ФП!


    1. vintage
      19.03.2017 21:47
      -1

      Идеал — ООРП :-)


      1. TheShock
        19.03.2017 21:53

        А есть интересные статьи на тему ООРП?


        1. vintage
          19.03.2017 22:09

          Конечно.


          Кроме того можно погуглить по следующим ключевикам: KnockoutJS, CellX, MobX,


          1. TheShock
            19.03.2017 22:20

            А что-то более абстрактное, теоретическое, а не привязанное к определенным библиотекам в JS?



  1. DeadKnight
    19.03.2017 22:22
    +1

    На самом деле, проблема этой статьи видна уже в первой строке:

    Заинтересовался темой функционального программирования, увидел здесь статью, и решил перевести


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


  1. kogoia
    19.03.2017 22:49

    В ООП тоже никто не отменял иммутабельность.

    Я бы так переписал приведённый пример:

        public interface IDoor 
        { 
            IDoor Open();
            IDoor Close();
            bool Locked();
        }
    
        public class OpendDoor: IDoor 
        {
            private readonly string _color;
            private bool _isOpend = true;
            public OpendDoor(string color) 
            {
                _color = color;
            }
    
            public IDoor Open() 
            {
                return this;
            }
    
            public IDoor Close() 
            {
                return new ClosedDoor(_color);
            }
    
            public bool Locked() 
            {
                return !_isOpend;
            }
        }
    
        public class ClosedDoor: IDoor 
        {
            private readonly string _color;
            private bool _isOpend = false;
            public ClosedDoor(string color) 
            {
                _color = color;
            }
    
            public IDoor Open() 
            {
                return new OpendDoor(_color);
            }
    
            public IDoor Close() 
            {
                return this;
            }
    
            public bool Locked() 
            {
                return !_isOpend;
            }
        }
    
        var myDoor = new OpendDoor("red");
        myDoor = myDoor.Close();
    


    1. lair
      20.03.2017 00:57
      +2

      … и зачем так сложно?

      Не говоря уже о том, что в ООП как-то принято[кем?] как раз изменяемое состояние, и есть ожидания, что метод Close не вернет новую дверь, а закроет существующую.


      1. TheShock
        20.03.2017 01:19
        +1

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


      1. areht
        20.03.2017 02:22

        Принято — это относительно. Половина заточенного на fluent возвращает новые классы.
        Хотя переименовать myDoor = myDoor.GetClosed(); для ожиданий было бы лучше


        1. lair
          20.03.2017 09:41
          +1

          Зависит от того, какой именно fluent. Например, builder часто просто мутирует внутренний объект конфигурации, и возвращает сам себя.

          А так — любые конвенции относительны.


      1. kogoia
        20.03.2017 20:51
        -1

        Это выглядит сложным и избыточным на таком простом примере.

        А может кадый раз содаётся новая вселенная когда её состояние меняется?! Или их изначально безконечное количество, а момент набудения реализует его в конкретном состоянии. )) Это в шутку.

        А вообще гараздо легче создать всё заного, чем задавать переход от каждого состояния в другое. Ведь если состоянии N количество, то возможность всех переходов N * (N-1). А создание всех возможных состоянии изначально, дает возможность описать программу декларативно. Будет писаться, не как доидти до конкретного состояния, а просто потребовать воссоздать конечный результат.

        Хорошим примером здесь будет, то как React подходит к решении этой проблемы в фронте.

        Кароче суть одна и та же, как я считаю.


        1. vintage
          20.03.2017 21:18

          Вам вовсе не нужно описывать все возможные переходы.


        1. lair
          20.03.2017 21:59
          +1

          Это выглядит сложным и избыточным на таком простом примере.

          Ну так приведите пример, где это не выглядит избыточным. Зачем нам плохие примеры?


          А может кадый раз содаётся новая вселенная когда её состояние меняется?!

          Угу. Накладные расходы посчитайте.


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

          Вам не нужны переходы из каждого состояния в каждое — только валидные. И, скажите мне, как вы создадите заново новое состояние на основании старого, не описав переход из старого состояния в новое?


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

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


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

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


          (кстати, интересно, как машины состояний пишутся на прологе)


          1. kogoia
            20.03.2017 23:24
            -1

            Ну так приведите пример, где это не выглядит избыточным. Зачем нам плохие примеры?

            Выглядит сложным и избыточным, совсем не означает, что он таким является. Ключевое слово «выглядит». А плохим примером, он вовсе не является и я такого не писал. Раз этот для вас плохой, может просвятите хорошим примером?!

            Угу. Накладные расходы посчитайте.

            Там был и второй вариант, но мне и первый нравится. Можете придумать свой и посчитать.

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

            Я сказал что если состоянии N количество, то возможность всех переходов N * (N-1). Ключевое слово «возможность».

            Серьезно?

            Да преставте себе такое, не трудно.

            new Sum(x, y).Result()
            


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

            Вот именно, нужно знать, каким условиям он удовлетворяет и я опишу это конечное состояние, удовлетворяя эти условия, а не путь как до него дойти с предыдущего состояния.
            Императивный код всегда можно спрятать под красивую абстракцию. (Это чтобы вы не подумали что я всегда буду писать декларативно и не буду пользоваться if-ом или о чём вы там подумаете). Если поддерживаемость кода важна, то к такому всегда нужно стремиться.

            (кстати, интересно, как машины состояний пишутся на прологе)

            Да мне тоже интересно, могли бы вы привести пример, а не писать раздражающие комментарии?!


            1. lair
              20.03.2017 23:59
              +1

              Выглядит сложным и избыточным, совсем не означает, что он таким является. Ключевое слово «выглядит».

              Ну тогда покажите, почему он не избыточный.


              Раз этот для вас плохой, может просвятите хорошим примером?!

              Нет, не просвещу.


              Там был и второй вариант, но мне и первый нравится.

              У второго варианта тоже очень высокие накладные расходы.


              Можете придумать свой и посчитать.

              Да легко. Изменяющееся состояние — O(1) по операциям, O(1) по памяти (для того же примера с дверью, конечно).


              Я сказал что если состоянии N количество, то возможность всех переходов N * (N-1). Ключевое слово «возможность».

              А зачем мне все возможные переходы?


              Да преставте себе такое, не трудно. new Sum(x, y).Result()

              Это не декларативное описание. Точнее, оно ничем не декларативнее x + y.


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

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


              Императивный код всегда можно спрятать под красивую абстракцию.

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


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

              К какому "такому"?


              Да мне тоже интересно, могли бы вы привести пример

              Нет, я не разбираюсь в Прологе.


            1. lair
              21.03.2017 00:14

              Раз этот для вас плохой, может просвятите хорошим примером?!

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


        1. AndreyRubankov
          21.03.2017 00:02
          +3

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


    1. potan
      20.03.2017 18:43

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


      1. lair
        20.03.2017 20:13

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

        В "классическом императивном программировании" это тоже прекрасно работает, безо всякого ООП.


        1. potan
          20.03.2017 20:30

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


          1. lair
            20.03.2017 21:55

            Ну на этом беседу можно и закончить, потому что ни к одному традиционному определению ООП это отношения не имеет.


          1. mdErrDX5341
            20.03.2017 22:17

            .


          1. mdErrDX5341
            20.03.2017 22:18

            ну тогда вообще не понятно что такое ООП
            http://eax.me/adt-and-traits/ я каждый раз попадаю не туды… извините, ответ на комментарий выше


            1. lair
              21.03.2017 11:26

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


              1. mdErrDX5341
                21.03.2017 22:52

                сразу определю константу, я = недомидл;
                определение у меня одно — «Должна быть золотая середина» — к этому я стремлюсь… все остальное полный идиотизм или фанатизм.
                каждый раз когда я слышу холивары по поводу ФП и ИП, TDD и количеством покрываемого кода, меня бросает в дрожь…
                Скажем так, я не представляю себе разработчика который не понимает ФП или понятия тестируемого кода, но есть методики для того что бы этого добится не выходя из дома, даже куча бесплатных курсов и видео.
                У всех свой опыт, каждый пришел(получил опыт) своим путем,
                допустим ТDD нужно на первых порах что бы уложить многие вещи в голове, вообще этот подход переворачивает мозг(для матерых программеров он не нужен).
                Так же ФП, такой подход переворачивает взгляд на программирование.
                ответ на вопрос: мне ближе постараться найти ту золотую середину, не более и не менее


                1. lair
                  21.03.2017 23:08

                  определение у меня одно — «Должна быть золотая середина»

                  Это не определение.


                  я не представляю себе разработчика который не понимает ФП

                  Посмотрите в пост.


                  ответ на вопрос: мне ближе постараться найти ту золотую середину, не более и не менее

                  Золотую середину между чем и чем, и какое отношение это имеет к тому, понимаете ли вы, что такое ООП?


                  1. mdErrDX5341
                    21.03.2017 23:19

                    вы как всегда сшибаете с ног))) это даже меня радует.

                    1) согласен, это не определение, скорее я так думаю.

                    2) не понял… ну думаю еще слабовато, хотя я сам ФП еще не особо понимаю

                    3) Золотую середину между методиками, процессом и т.д., наверное я слишком глупо об этом пишу, но мне кажется(подчеркиваю «мне кажется»), что надо найти золотую середину между всех этих инструментах в программировании


                    1. lair
                      21.03.2017 23:43

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


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


                      1. mdErrDX5341
                        22.03.2017 00:02

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


                        1. lair
                          22.03.2017 10:13

                          В контексте данного разговора — ООП, например.


                  1. mdErrDX5341
                    21.03.2017 23:22

                    2) опять же это мое мнение…
                    надо развиваться и взгляд с другой стороны на разработку ПО должен быть, ФП это одна из возможностей


    1. lair
      21.03.2017 00:53

      И еще раз кстати. Уж если вы говорите о выражении доступных состояний, то:


          interface IDoor  
          { 
              bool IsOpen {get;}
          }
      
          interface IClosedDoor: IDoor
          { 
              IOpenDoor Open();
          }
      
          interface IOpenDoor: IDoor
          { 
              IClosedDoor Close();
          }

      Но мы, по факту, пришли к нормальному такому типу-перечислению, осталось только избавиться от IsLocked в пользу type tag.


      1. mdErrDX5341
        21.03.2017 23:31

        так много интерфейсов… кажется что здесь нет абстракций, а какая-то функциональщина.


        1. lair
          21.03.2017 23:44

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


          1. mdErrDX5341
            22.03.2017 00:06

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


            1. lair
              22.03.2017 10:13

              скорее всего проблема уже складывается в том что нужна предметная область, а уже потом городить кучу интерфейсов…

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


          1. mdErrDX5341
            22.03.2017 00:31

            просто я не понимаю чем выше привиденный пример лучше чем
            doorOpen :: Boolean, в плане того что мы не знаем предметной области, так для шутки…


            1. lair
              22.03.2017 10:14

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


              1. mdErrDX5341
                26.03.2017 22:13

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


                1. lair
                  26.03.2017 22:35

                  Интерфейс как мне кажется это нереализованный протокол,

                  Нет, интерфейс — это формализованная договоренность.


                  Но все равно не понятно для какого случая столько интерфейсов?

                  Не "столько интерфейсов", а "столько типов". Для случая, когда каждое состояние описано типом.


                  Может в таком случае выделить дверь как сущность?

                  Ну так она и выделена.


                  для этого надо только будет определить возможные состояния

                  Они и определены: закрыто и открыто.


                  1. mdErrDX5341
                    26.03.2017 23:49

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

                    «Не „столько интерфейсов“, а „столько типов“. Для случая, когда каждое состояние описано типом.» — Вы сейчас это оговариваете в ФП стиле? или я ошибаюсь?(я с Вами согласен в таком случае, да и вообще согласен)

                    «Может в таком случае выделить дверь как сущность?» — интерфейс не выделяет сущностей, я с Вами не соглашусь если вас правильно понял.

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


                    1. mdErrDX5341
                      27.03.2017 00:03

                      *на автомате скопировал*
                      «Ну так она и выделена.» — это интерфейс, но не реализация


                    1. lair
                      27.03.2017 01:54
                      -1

                      о чем я и говорю, но протокол это уже реализованная…

                      Нет, "протокол" — это тоже договоренность. Реализация существует отдельно.


                      Вы сейчас это оговариваете в ФП стиле?

                      Нет, не важно, ООП или ФП.


                      интерфейс не выделяет сущностей

                      Почему это?


                      это интерфейс, но не реализация

                      И что? Для доменной модели это не важно.


                      Вы определили интерфейсы, но к двери(как к модели предметной области это не как не относится

                      Почему не относится?


                      1. mdErrDX5341
                        27.03.2017 02:09

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

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

                        3)это интерфейс, но не реализация — `И что? Для доменной модели это не важно.` — доменная модель также проекцируется и на реализацию, если не реализовывать в рамках доменной модели, тогда и модель теряется…

                        4) Вы определили интерфейсы, но к двери(как к модели предметной области это не как не относится

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


                        1. lair
                          27.03.2017 02:13

                          описать каждое состояние типом… ну мне кажется это уже перебор

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


                          тут скорее всего надо включать не типы а абстракции и коллекции типов… вообщем лучше абстрагироваться…

                          Тип — это и есть абстракция.


                          доменная модель также проекцируется и на реализацию,

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


                          вы не определили сам контекст

                          Контекст определен постом.


                          но где их оправдание

                          Их оправдание — желание статической верификации корректных переходов.


                          1. mdErrDX5341
                            27.03.2017 02:25
                            -2

                            > описать каждое состояние типом… ну мне кажется это уже перебор

                            Зависит только от того, насколько сильные гарантии вы хотите в статическом анализе. Кто-то вообще считает статические системы типов перебором.
                            ________________
                            ну бред и перебор… можете хоть 30 минусов поставить, но это перебор… это как покрытие тестами на 100000… процентов на количество строк.

                            ~~~~
                            вернемся к вашим словам
                            > Не «столько интерфейсов», а «столько типов». Для случая, когда каждое состояние описано типом.
                            ____
                            Вы можете предугадать каждое состояние и описать его типом? или все же вернемся к абстракциям?
                            ~~~~~
                            > вы не определили сам контекст

                            Контекст определен постом.

                            ____
                            ну я отвечаю не на пост, а на ваши комментарии, также как и Вы на мои.

                            ~~~
                            last — посмеялся))


                            1. mdErrDX5341
                              27.03.2017 02:42

                              я не могу удержаться)))
                              давай еще минус))) ананимус))


                            1. lair
                              27.03.2017 11:39

                              ну бред и перебор…

                              Что "бред и перебор"? Статические системы типов?


                              Вы можете предугадать каждое состояние

                              Мне не надо их предугадывать, они описаны в задаче.


                              или все же вернемся к абстракциям?

                              Тип — это и есть абстракция.


                              ну я отвечаю не на пост, а на ваши комментарии, также как и Вы на мои.

                              Тем не менее, мои комментарии существуют в контексте поста.


                  1. mdErrDX5341
                    26.03.2017 23:57

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


                    1. mdErrDX5341
                      27.03.2017 02:14

                      давай еще минус))) ананимус))


      1. mdErrDX5341
        21.03.2017 23:40

        если к этому прибавить preg maching то получается совсем ерунда и излишества
        Object -> close or open
        function switch()…


        1. lair
          21.03.2017 23:46

          "Если бы у бабушки были яйца..."


          Это не то что бы излишества, это пример type-driven-программирования в парадигме, которая для этого не очень подходит. Зато статическое выражение возможных переходов и операций.


          1. mdErrDX5341
            22.03.2017 00:08

            все равно как-то излишне


            1. lair
              22.03.2017 10:15

              Так и изначальный пример был избыточен, потому что нет никакого смысла в иммутабельности для такой задачи. Но уж если мы решили брать иммутабельность, то почему бы заодно и не взять type-driven?


              1. mdErrDX5341
                23.03.2017 00:12

                вот тут я туплю если честно.
                в плане определения type-driven. Пример явно глупый, настолько глупый что он не показывает даже 30% ФП, но я не думаю что в данном случае надо применять ООП для примера, скорее надо показывать примеры из ФП, то есть вместо осуждения, привести примеры где это может пригодится. Замечу еще раз… Я могу ошибаться.


          1. mdErrDX5341
            22.03.2017 00:14

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


            1. TheShock
              22.03.2017 02:08

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

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

              bool isDoorOpened = true;
              
              isDoorOpened = false; // закрыли
              isDoorOpened = true; // открыли
              

              А дальше просто усложняем соответственно необходимым бизнес-требованиям.


              1. mdErrDX5341
                22.03.2017 23:48
                -1

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


                1. lair
                  23.03.2017 00:05

                  Дело не в создании двери, а в ответе, скажем так, на Ваш вопрос что это за дверь

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


                  1. mdErrDX5341
                    23.03.2017 00:15

                    технически… я сейчас рассуждаю о императивном и декларативном стиле


                    1. lair
                      23.03.2017 00:19

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


                      1. mdErrDX5341
                        23.03.2017 00:22

                        getDoor(val)

                        dor a = |
                        |
                        |
                        |


                        1. lair
                          23.03.2017 00:23

                          И какой из них какой?


                          (вторую запись, впрочем, я вообще не могу прочитать)


                          1. mdErrDX5341
                            23.03.2017 00:24

                            вторая запись это preg maching


                            1. lair
                              23.03.2017 00:27

                              preg matching — это что-то из PHP, я так понимаю? то есть, императивный стиль? Извините, но что он делает, понять невозможно.


                              А вот первая ваша запись (getDoor(val)) может быть как из процедурного (а они императивны), так и из функционального (а они считаются декларативными) языка, так что и вовсе не понятно, что вы чему противопоставляете.


                      1. mdErrDX5341
                        23.03.2017 00:23
                        -1

                        я устал, Вы и так знаете что я меньше вас знаю и у меня меньше практики… так зачем этот каламбур?


                        1. mdErrDX5341
                          23.03.2017 00:27
                          -1

                          давай еще минус))) ананимус))


                  1. mdErrDX5341
                    23.03.2017 00:19
                    -1

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


                    1. mdErrDX5341
                      23.03.2017 00:27
                      -1

                      давай еще минус))) ананимус))


                1. mdErrDX5341
                  23.03.2017 00:14
                  -1

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


                  1. mdErrDX5341
                    23.03.2017 00:27
                    -1

                    давай еще минус))) ананимус))


                1. TheShock
                  23.03.2017 00:41

                  Дело не в создании двери, а в ответе, скажем так, на Ваш вопрос что это за дверь, можно на каком-то этапе забыть про то как работает ПК. код вам просто возвращает дверь к которой вы обратились и т.д… просто попробуйте ФП язык

                  Простите, у вас какая-то каша. Как минимум в комметарии. Что-то намешали — на разгребтись.
                  Я прекрасно понимаю концепцию ФП, к чему это ваше «попробуйте»?

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

                  Вы можете себе представить крупное приложение на SQL? И еще вопрос:
                  const open = obj => Object.assign({}, obj, {locked: false}) 
                  


                  Вы считаете, что это декларативно? Обычная императивщина. Я не понимаю, почему ФП называют декларативным. Практически все примеры, которые я видел что из практики, что из комментариев «отличные примеры ФП» — глубоко императивны — «сделай А, сделай Б, сделай В». Иногда проскакивает декларативность, но она точно так же проскакивает и в других парадигмах.


                  1. mdErrDX5341
                    27.03.2017 00:12
                    -1

                    list = door(state='close')


                    1. TheShock
                      27.03.2017 15:11
                      +1

                      А почему list? С каких пор дверь — список?


                  1. mdErrDX5341
                    27.03.2017 00:20
                    -3

                    это такой намек…
                    DDD — проектируйте модель — подберите парадигму — да вообще проектируйте моделью предметной областью.

                    декларативный
                    императивный
                    сумашедший
                    недоразвитый

                    включайте ум… ум… ум… о… грибок)))) о чем я?
                    я не вижу смысла обсуждать с Вами эти вопросы.


                    1. TheShock
                      27.03.2017 15:10
                      +2

                      включайте ум

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

                      Из-за этого все остальное не понял.


            1. lair
              22.03.2017 10:15

              Я очень рад, что вам в вашей задаче нет смысла городить кучу интерфейсов.


              1. mdErrDX5341
                22.03.2017 23:36

                Эх не могу плюсануть, но я думаю что я еще не дорос до такого диалога, еще слаб в знаниях и практике… но спасибо за feedback.


              1. mdErrDX5341
                27.03.2017 00:38
                -1

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


  1. vadim_ig
    20.03.2017 11:01
    +3

    Классическая статья по функциональному программированию на хабре
    1. ООП — плохо
    2. Надуманный простенький пример, на основе которого делаются далеко идущие выводы
    3. Три строчки, запланированные на статью, израсходованы, поэтому до свидания!


    1. vasya-ves
      20.03.2017 11:07
      -3

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


      1. lair
        20.03.2017 11:22
        +3

        Ну так надо же выбирать, что переводите.


        1. vasya-ves
          20.03.2017 15:25

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


          1. lair
            20.03.2017 15:34
            +3

            Но получается, что там не качественные статьи выкладывают?

            Получается так.


            Просто не надо переводить статью по теме, в которой вы ничего не понимаете. Это со всех точек зрения опасно.


      1. vadim_ig
        20.03.2017 11:44

        Я читал заголовок. И он о функциональном программировании во фронтэнде. Единственный же приведенный пример в статье — какая-то непонятная дверь. Если она и имеет какое-то отношение к фронтэнду, то это никак не поясняется. Или тему раскрывает список ссылок в конце? Тогда это совсем несерьезно. Ну а то что это перевод, автоматически качество материала не повышает.


  1. michael_vostrikov
    20.03.2017 11:48

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


    Делал как-то в университете лабу на Прологе с GUI. Так себе удовольствие. Например, надо как-то отрисовывать меню на экране, хранить номер выделенного пункта и при этом реагировать на нажатия клавиатуры, изменяя его. Это помимо основного состояния, которое тоже меняется при выполнении команды меню. Хранил счетчики во встроенной базе данных. Может и по-другому как-то можно было.


    1. mdErrDX5341
      20.03.2017 22:21

      под любым ФП лежит ИП(императивное программирование, ну оно как бы выросло из инструкций ЦП)


  1. mdErrDX5341
    20.03.2017 13:58
    +2

    Чтобы заинтересовать лучше почитать
    https://github.com/MostlyAdequate/mostly-adequate-guide-ru,
    а так лучше попробовать изучить haskell или другой функциональный язык. А такие примеры только убивают интерес к ФП…