JS ФП тезисы: различия между версиями
imported>Supportadmin Нет описания правки |
imported>Supportadmin Нет описания правки |
||
Строка 3: | Строка 3: | ||
*[https://rsdn.ru/forum/decl/4047805.all Что такое монады? (форум)] | *[https://rsdn.ru/forum/decl/4047805.all Что такое монады? (форум)] | ||
==Парадигмы (стили) программирования== | |||
Языки программирования состоят из операторов, условных операторов, операторов цикла и функций. Наличие условных операторов и операторов циклов являются отличительными чертами "императивных языков программирования". Функциональные языки, как правило, поддерживают только операторы и функции. | Языки программирования состоят из операторов, условных операторов, операторов цикла и функций. Наличие условных операторов и операторов циклов являются отличительными чертами "императивных языков программирования". Функциональные языки, как правило, поддерживают только операторы и функции. | ||
Строка 28: | Строка 29: | ||
return accumulator; | return accumulator; | ||
}</nowiki> | }</nowiki> | ||
Как мы видим, объектно-ориентированный вариант похож на императивную версию, кроме того, что функция (метод) теперь метод класса. Объектно-ориентированные языки, как правило, императивных языков также. | |||
Теперь запишем функциональную версию этой функции. | |||
С точки зрения программиста '''монада''' - это абстрактный контейнер с тремя функциями. | С точки зрения программиста '''монада''' - это абстрактный контейнер с тремя функциями. |
Версия от 09:37, 27 мая 2015
Источники
Парадигмы (стили) программирования
Языки программирования состоят из операторов, условных операторов, операторов цикла и функций. Наличие условных операторов и операторов циклов являются отличительными чертами "императивных языков программирования". Функциональные языки, как правило, поддерживают только операторы и функции.
Интересно, что ни один из трех языков, Java, C ++ и C, не являются функциональными языками программирования.Язык C - императивный язык программирования, C ++ и Java, императивный / объектно- ориентированные языки программирования. Т.е. существуют три парадигмы (стиля) программирования: императив, объектно-ориентированный и функциональный. Существует еще один, декларативный стиль.
Различия между этими парадигмами заложены в основе. Императив и объектно-ориентированное программирование основано на «машине Тьюринга». Функциональное программирование на базе "лямбда-исчисления", а декларативное программирование основано на «логике первого порядка". Будут рассмотрены различия между, императивным, объектно-ориентированным и функциональном программировании на практическом уровне.
В императивном языке программирования изменение состояния программы достигается путем выполнения серии операторов, и выполняет контроль потока, прежде всего, с помощью условных операторов, операторов цикла и вызовов функций. Программа, приведенная ниже простая реализация метода JavaScript Array.join в императивном стиле.
function simpleJoin(stringArray) { var accumulator = ''; for (var i=0, l=stringArray.length; i < l; i++) { accumulator = accumulator + stringArray[i]; } return accumulator; }
Код выше - последовательный. Мы перебераем массив и добавить каждый элемент в строку-аккумулятор и возвращаем аккумулятор. Сейчас мы перепишем эту функцию в объектно-ориентированном способом. Так как JavaScript имеет класс Array, мы добавим этот метод для класса Array, так что каждый экземпляр этого класса получит доступ к этой функции. JavaScript использует наследование через прототипы и поэтому мы добавляем эту функцию, в прототип массива.
Array.prototype.simpleJoin = function() { var accumulator = ""; for (var i=0, l=this.length; i < l; i++) { accumulator = accumulator + this[i]; } return accumulator; }
Как мы видим, объектно-ориентированный вариант похож на императивную версию, кроме того, что функция (метод) теперь метод класса. Объектно-ориентированные языки, как правило, императивных языков также.
Теперь запишем функциональную версию этой функции.
С точки зрения программиста монада - это абстрактный контейнер с тремя функциями.
- map — заменяет содержимое контейнера без изменения самого контейнера. Заменяем каждый гвоздь в коробке шурупом, каждый int в массиве float-ом — так map и работает.
- unit — берет элемент и возвращает контейнер с одним этим элементом. Делаем из гвоздя коробку с одним гвоздем. Делаем из int массив из одного int.
- join — уменьшает вложенность контейнеров — из коробки коробок гвоздей делает коробку с гвоздями (из массива массивов int-ов — массив int-ов). Ну или из коробки коробок коробок гвоздей делаем коробку коробок гвоздей. Это уже сложная концепция, доступная только программистам и более абстрактно развитым товарищам; обычный человек будет обескуражен тем, как в одну коробку могли поместиться несколько точно таких-же коробок. Впрочем, простая замена коробок коробок на мешки мешков или пакеты пакетов позволяет совершить абстрактно-теоретико-категориальный прорыв.
Монада - это интерфейс с двумя методами:
- "поднять в монаду". Давайте называть этот метод 'pure'. Функция от одного аргумента. На входе какое-то значение, на выходе это же значение, но помеченое другим типом.
- "применить функцию к значению в монаде" или "совершить действие". В энергичном языке, думаю, уместо было бы название 'apply'. Функция от двух аргументов. На входе монадическое значение (полученное из первой функции) и собственно функция-действие, которое нужно применить к первому аргументу. На выходе новое монадическое значение, то есть изменённое функцией-действитем. Ну, эта особенность с "на выходе новое", она в общем-то нужна в языках с одним присваиванием, в остальных можно передать монадическое значение по ссылке и поменять его.
Всё остальное относится к конкретным монадам и рассматривать их нужно отдельно.
Собственно, весь смысл в двух вещах:
- новый тип даёт инкапсуляцию
- явная передача функции-действия развязывает (decoupling) их от собственно процесса применения действия. И основная фишка в том, что этот, своего рода, late binding может происходить не в рантайме (как в технологии COM, если знаете), а во время компиляции. С хорошей поддержкой полиморфизма в системе типов можно:
- гибко определять как будут выполняться одинаковые действия в разных монадах
- повторно использовать однажды определённые действия в новых монадах.