Основы функционального программирования за 7 минут

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

Чистота

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

var z = 10;
function add(x, y) {
    return x + y;
}

Обратите внимание, что функция add никак не затрагивает переменную z. Она не читает значение z и ничего в нее не записывает. Она только принимает x и y и возвращает результат их сложения.

Функция add – чистая функция. Как только она будет работать со сторонними параметрами, например с переменной z – она больше не будет чистой.

Вот пример другой функции:

function justTen() {
    return 10;
}

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

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

Разберем еще один пример.

function addNoReturn(x, y) {
    var z = x + y
}

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

Посмотрим, как будет работать функция add.

function add(x, y) {
    return x + y;
}
console.log(add(1, 2)); // вернет 3
console.log(add(1, 2)); // все еще 3
console.log(add(1, 2)); // всегда 3

console.log(add(1, 2)) – всегда будет возвращать 3. Не большой сюрприз, конечно. Но это так, только потому, что add – чистая функция. Используй она в обработке параметров переменные извне и ее поведение стало бы непредсказуемым.

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

Побочные эффекты

Поскольку чистая функция не может взаимодействовать с внешними значениями, все следующие функции не будут являться чистыми:

writeFile(fileName);
updateDatabaseTable(sqlCmd);
sendAjaxRequest(ajaxRequest);
openSocket(ipAddress);

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

Императивные языки программирования, такие как JavaScript, Java или C# имеют побочные эффекты всюду. Это делает отладку программы сложной, ведь переменные могут быть изменены в любом месте. И когда значение переменной изменится на неверное или сделает это не в то время, где придется искать ошибку? Везде? Это нехорошо.

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

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

Неизменяемость

Классический пример работы с переменными обычно не вызывает недоумения:

var x = 1;
x = x + 1;

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

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

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

addOneToSum y z =
    let
        x = 1
    in
        x + y + z

addOneToSum здесь – функция, принимающая 2 параметра – y и z.

В блоке let переменная x получает значение 1, то есть теперь она равняется единице до конца своего существования.

В блоке in происходит вычисление x + y + z с использованием переменных, объявленных в let, а именно x. В итоге функция вернет значение 1 + y + z.

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

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

А циклов в привычном функциональном программировании попросту нет. Это значит, что такие конструкции как for, while, do, repeat – не используются. Для создания циклов в функциональном программировании используется рекурсия.

Циклы в функциональном программировании

В JavaScript есть два способа создания циклов:

// простая конструкция цикла

var acc = 0;
for (var i = 1; i <= 10; ++i)
    acc += i;
console.log(acc); // выведет 55

// цикл без специальной конструкции и переменных (рекурсия)

function sumRange(start, end, acc) {
    if (start > end)
        return acc;
    return sumRange(start + 1, end, acc + start)
}
console.log(sumRange(1, 10, 0)); // выведет 55

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

В языке Elm такие конструкции проще читать и понимать:

sumRange start end acc =
    if start > end then
        acc
    else
        sumRange (start + 1) end (acc + start)

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

Читайте также:

Функциональное программирование: рефакторинг, замыкания и функции высшего порядка

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

admin
30 июня 2018

Шаблоны проектирования в Python: для стильного кода

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