- PVSM.RU - https://www.pvsm.ru -
Примечание переводчика: Есть два понятия — параллельность (выполнение одновременно, независимо) и конкурентность (выполнение по шагам, поочерёдно, но одновременно несколько задач) и как всегда, мне пришлось поломать голову подобрая правильные термины.
Некоторые слова или термины я буду дублировать в скобках в оригинале, для того, чтобы искать по англоязычным терминам дополнительную информацию, которой будет в разы больше.
Возможно вы уже слышали такое выражение, вроде: “Clojure”, “Scala”, “Erlang” или даже “Java теперь имеет лямбды”. И вы имеете хоть и отдалённое представление о «Функциональном программировании». Если вы участник какого-либа программисткого сообщества, тогда эта тема могла уже вами обсуждаться.
Если вы поищите в Google по словосочетанию «Функциональное программирование», вы не увидите что-то нового. Второй язык из созданных ранее уже охватывает эту тему, он был создан в 50-ых и называется Lisp. Тогда, какого чёрта, эта тема стала популярна только сейчас? Всего то 60 лет спустя?
Верите вы этому или нет, но компьютеры были нааамного медленнее чем DOM. Нет, действительно. И в то-же время были 2 основные идеи в соглашении по дизайну и реализации языков программирования:
Компьютеры не имели достаточно вычислительных мощностей, чтоб иметь дело со всеми абстракциями и справляться с программами, написанными в функциональном стиле. Так Lisp выдыхался раньше, будучи чрезвычайно медленным и следовательно, не пригодным для работы. Тогда-то и началось господство императивного стиля программирования, особенно с расцветом C.
Сейчас стало практически нормальным использовать большинство приложений, совершенно не заботясь на каком языке они были написаны. Наконец-то функциональные языки получили второй шанс.
Эта статья, ни в коем случае, не введение в ФП. В конце этого раздела вы должны будете знать, что из себя представляет ФП и с чего начать своё путешествие по изучению.
Вы можете понимать термин «Функциональное программирование» слишком буквально, как программирование с использованием функций и это недалеко от истины. Вы будете создавать функции в терминах других функций и писать функции (Вы помните f ∘ g из школьной программы? Сейчас вам это пригодится). Это всё.
Список (не полный) особенностей ФП:
Сейчас вы не должны переживать об этих странных терминах, просто поймите что они означают.
Функции первого класса значит, что вы сможете сохранять функции в переменные. Я уверен вы делали что-то похожее, как в примере на JavaScript:
var add = function(a, b){
return a + b
}
Вы только что создали анонимную функцию, которая получает a и b и возвращает a + b в переменную add.
Функции высшего порядка значит, что функции могут возвращать функции или принимать функции как параметры.
И снова на JavaScript:
document.querySelector('#button')
.addEventListener('click', function(){
alert('yay, i got clicked')
})
или
var add = function(a){
return function(b){
return a + b
}
}
var add2 = add(2)
add2(3) // => 5
Оба варианта пример функций высшего порядка, даже если вы не писали что-то подобное, вы возможно видели похожее ещё где-то.
Чистые функции значит, что функция не меняет переменные, она просто принимает данные и возвращает данные, как наши любимые функции из математики. Так-же это значит, что если вы вызовите функцию f с аргументом 2 и она возвращает 10, то она всегда будет возвращать 10. Не имеет значение какое окружение, количество нитей или порядок выполнения. Они не вызывают никаких побочных эффектов в других частях программы и это действительно мощная концепция.
Замыкания значит, что вы можете сохранять некоторые данные внутри функции, которые будут доступны в специфичной возвращаемой функции, другими словами возвращаемая функция хранит свою среду выполнения.
var add = function(a){
return function(b){
return a + b
}
}
var add2 = add(2)
add2(3) // => 5
Снова взгляните на второй пример из параграфа Функции высшего порядка, переменная a была замкнута и доступна только в возвращаемой функции. На самом деле, замыкания не особенность ФП парадигмы, скорее оптимизация.
Неизменяемое состояние значит, что вы вообще не можете менять любые состояния (хотя можете создать новые). В следующем коде (на OCaml), вы присвоили переменной x значение 5 и x всегда будет 5.
let x = 5;;
x = 6;;
print_int x;; (* prints 5 *)
Эти особенности выглядят достаточно странно, но вы скоро поймёте как они облегчат вашу жизнь.
Это многообещающее время, когда мы сможем иметь распределённые и многопоточные приложения, наконец-то наступило. К сожалению, наша существующая (или наиболее используемая) модель не готова к многопоточности (concurrency) и параллельности (parallelism), хотя она и решает текущие задачи, но и добавляет большие проблемы.
Чтобы улучшить приложения, мы нуждаемся в простом и надёжном способе добиться желаемого. Вы помните выше упомянутые особенности ФП? Чистые функции и неизменяемое состояние? Правильно, вы можете выполнять функции тысячи раз, на разных ядрах или машинах и результат будет всегда одинаковым. И так, мы можем один и тот-же код запускать и на одном ядре и на тысячах. Жизнь опять становится безоблачной.
По крайней мере, для многопоточности и параллельности ООП не может вас больше выручить. Потому, что ООП относится к стилю с изменяемым состоянием (в императивных языках, которые написаны в ООП стиле, в большинстве случаях). Вызываемые методы объекта предполагают изменять текущие self или this. Придётся приложить достаточно усилий, чтобы корректно обновлять и синхронизировать все потоки.
Пишу это не для того, чтобы агитировать вас переходить на ФП с тех парадигм, которые вы сейчас используете (хотя некоторые люди скажут я должен), но вы однозначно должны усвоить: Java и C++11 уже имеют лямбда исчисления. Могу сказать, что почти все современные и поддерживаемые языки собираются реализовать ФП особенности или уже сделали это.
Стоить отметить, что мы не должны прекращать использовать изменяемое состояние. Мы должны использовать ввод/вывод (IO) и т.д., чтобы наши программы были полезны. Основная идея ФП является: используй изменяемое состояние, только тогда, когда это действительно необходимо.
Да.
Функциональное Программирование поможет вам писать программы лучше и рассуждать о проблемах, которые вам придётся решать.
Начинать всегда трудно в любой области. Уверен, вы начали изучать программирование тоже имея кучу проблем, даже в ООП языках. Возможно начинать писать в ООП стиле было проще, чем писать свою первую программу потому, что вы уже были знакомы с некоторыми общими идиомами, вроде объявление переменных и for/while циклами.
Начинать изучать ФП — это почти тоже самое, как снова начать писать программы с нуля (вне зависимости какой язык вы начали изучать, это будет однозначно как начать с самого начала).
Многие могут отметить, что ФП трудночитаемый. Если у вас опыт в императивных языках, функциональные программы будут выглядеть как тайнопись. И не потому, что это действительно так, а потому, что вы не знаете его основные идиомы. Однажды, поняв фундаментальные принципы, программы станут на много более читаемыми.
Просмотрите программу написанную на Haskell и JavaScript (в императивном стиле):
guess :: Int -> [Char]
guess 7 = "Much 7 very wow."
guess x = "Ooops, try again."
-- strongly inspired by http://learnyouahaskell.com
function guess(x){
if(x == 7){
return "Much 7 very wow."
}
else {
return "Oops, try again."
}
}
Это очень простая программа. Она выводит поздравительное сообщение, когда пользователь угадал и ввёл цифру 7 или выведет сообщение об ошибке во всех других случаях. Возможно это выглядит шифровкой, как Haskell может делать всю работу всего в две строки кода (первую строку вы можете игнорировать, это просто «объявление типа»). Но это станет достаточно простым, однажды, поняв возможности сопоставления с образцом (Pattern Matching) (которые реализованы не только в ФП языках, но были их особенностью).
Что делает Haskell:
Если принимаемый аргумент у функции guess равен цифре 7, то она вернёт «Much 7 very wow.» или вернёт «Oooops, try again.» в других случаях.
И это тоже самое, что делает код на JavaScript, но Haskell сопоставляет с «образцом», объявленным программистом в коде.
Данный подход может показаться не очень полезным в данном случае, если вы можете использовать if/else. Но это станет действительно полезным, когда вы сами начнёте писать более сложные структуры данных.
plus1 :: [Int] -> [Int]
plus1 [] = []
plus1 (x:xs) = x + 1 : plus1 xs
-- plus1 [0,1,2,3]
-- > [1,2,3,4]
В программе выше, *plus1* функция, которая принимает список целых чисел и прибавляет по 1 к каждому элементу списка. Функция сопоставляет, когда список пустой [] (возвращает другой пустой список, раз в нём нет элементов) обходит не пустой список и определяет образец сопоставления: x как первый элемент списка, xs как оставшийся список. Потом просто считает сумму и объединяет через рекурсивный вызов.
Я уверен, вы потратите много минут (не самых приятных), переписывая данный пример в императивном стиле, уместив код в две строки, и при этом, сохранив читаемость.
Вышло много материалов по Функциональному программированию, но эти ссылки вы не должны пропустить однозначно:
К сожалению, курсы будут доступны только в конце года. Но вы можете следить за контентом и видео, они доступны на Youtube.
С другой стороны, если вы предпочитаете текстовые материалы, я непременно рекомендую некоторые из них:
Первые две имеют похожие учебные планы, познакомят вас с базисом Функционального программирования и очень подходят для начинающих. Третья из ссылок, это курс Парадигм компьютерного программирования, охватывает больше, чем Функциональное программирование. Важно отметить, что эти материалы для начального уровня.
Кроме того, Крис Аллен (Chris Allen) [7] написал отличную статью по изучению Функционального программирования. Она называется Functional Education [8] и имеет исчерпывающий список материалов для изучения Функционального программирования используя Haskell, а так же расскажет о сильных и слабых сторонах этого подхода. Следуя рекомендованным Крисом ссылкам, вы сможете изучить начальные принципы и более сложные темы (я уверен вы слышали о монадах) Функционального программирования и возможно поймёте как писать приложения используя их. (Спасибо тебе Крис, за ссылки на материалы.)
Удачи в вашем Функциональном Новом Году! ☺
Автор: greg_fat
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/97287
Ссылки в тексте:
[1] архитектуры фон Неймана: https://ru.wikipedia.org/wiki/%D0%90%D1%80%D1%85%D0%B8%D1%82%D0%B5%D0%BA%D1%82%D1%83%D1%80%D0%B0_%D1%84%D0%BE%D0%BD_%D0%9D%D0%B5%D0%B9%D0%BC%D0%B0%D0%BD%D0%B0
[2] Principles of Functional Programming in Scala: https://www.coursera.org/course/progfun
[3] Paradigms of Computer Programming — Fundamentals: https://www.edx.org/course/paradigms-computer-programming-louvainx-louv1-1x#.VKWU9aYVlpk
[4] Structure and Interpretation of Computer Programs: https://mitpress.mit.edu/sicp/full-text/book/book.html
[5] How to Design Programs: http://htdp.org/
[6] Concepts, Techniques, and Models of Computer Programming: http://www.amazon.com/Concepts-Techniques-Models-Computer-Programming/dp/0262220695
[7] Крис Аллен (Chris Allen): https://twitter.com/bitemyapp
[8] Functional Education: http://bitemyapp.com/posts/2014-12-31-functional-education.html
[9] Источник: http://geektimes.ru/post/261144/
Нажмите здесь для печати.