[Переклад] Не варто боятися функціонального програмування

    Представляю вашій увазі переклад прослизнув недавно в посиланнях дайджесту статті Джонатана Моргана про функціональне програмуванні на прикладі JavaScript. Матеріал розрахований на початківців, але проте він досить цікавий.
 
Буду вдячний за конструктивні зауваження та пропозиції щодо друкарські помилки, перекладу та / або оформлення. Приємного читання!
 
 
 

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

 Функціональне програмування — вусатий хіпстер від парадигм програмування. Будучи продуктом часів академічного становлення комп'ютерних наук, функціональне програмування не так давно пережило відродження завдяки великій користі при використанні в розподілених системах (і, ймовірно, завдяки тому, що «чисті» функціональні мови начебто Haskell непросто зрозуміти, що також накладає свій відбиток).
 
Більш строгі функціональні мови програмування, як правило, використовуються, коли продуктивність і злагодженість критичні — наприклад, якщо програма завжди повинна робити саме те, що від неї очікується, і повинна працювати в середовищі, де завдання можуть бути розділені між сотнями і тисячами об'єднаних в мережу комп'ютерів. Clojure, наприклад, лежить в основі Akamai, величезної мережі доставки контенту, використовуваної компаніями на зразок Facebook, а Twitter відмінно адаптував Scala для своїх самих вимогливих до продуктивності компонентів, а AT & T використовує Haskell для систем безпеки своїх мереж.
 
Для більшості фронтенд-розробників ці мови мають круту криву навчання; проте, багато більш прості і доступні мови мають риси функціонального програмування — хоча б той же Python з його стандартної бібліотекою і її функціями на зразок
map
і
reduce
(про які ми ще поговоримо) і сторонніми бібліотеками начебто Fn.py, або ж JavaScript, який активно використовує методи роботи з колекціями і має бібліотеки начебто Underscore.js і Bacon.js.
 
 
 
Функціональне програмування, звичайно, може здаватися складним, але потрібно пам'ятати, що воно створене не тільки для докторів наук, прихильників науки про дані і гуру архітектури систем. Для більшості справжня користь від функціонального стилю в тому, що програми можуть бути розділені на дрібні і прості частини, більш надійні і значно зрозуміліші одночасно. Якщо ви — фронтенд-розробник, який працює з даними, особливо якщо використовуєте D3 , Raphael або схожі бібліотеки для візуалізації, то функціональне програмування може стати серйозною зброєю у вашому арсеналі.
 
Знайти суворе визначення функціонального програмування непросто, і велика частина літератури покладається на твердження на кшталт «ну, там функції — об'єкти першого класу» і «зникають побічні ефекти». Якщо це ще не порвало ваш мозок на шматочки, то ближче до теорії функціональне програмування часто пояснюється в термінах лямбда-числення (хоча деякі стверджують, що функціональне програмування, в принципі, просто математика), але прошу, не турбуйтеся. Насправді новачкові досить зрозуміти тільки дві ідеї для того, щоб використовувати функціональне програмування для своїх щоденних завдань (і без всяких лямбда!).
 
По-перше, при функціональному підході дані повинні бути незмінні (іммутабельни), що звучить важкувато, але це просто означає, що вони не можуть змінюватися. На перший погляд це може виглядати дивно (зрештою, кому потрібна програма, яка нічого не змінює?), Але на ділі ви просто постійно створюєте нові структури даних замість зміни існуючих. Наприклад, якщо вам потрібно зробити щось з масивом, ви створюєте новий масив з новими значеннями замість зміни старого масиву. Просто ж!
 
По-друге, програми у функціональному стилі не повинні мати стан, що, загалом-то, значить, що вони повинні виконуватися так, як ніби до них ніхто нічого не робив, і без інформації про те, що могло або не могло статися в програмі раніше (можна сказати, що програма без стану не враховує своє минуле). Разом з незмінюваність це дозволяє сприймати кожну функцію так, як ніби вона працює у вакуумі, блаженно забиваючи на все інше, що є в програмі, крім інших функцій. Ще це значить, що функція працює тільки з даними, переданими в якості параметрів, і тому може виконувати свою роботу незалежно від якихось зовнішніх значень.
 
Незмінюваність даних і відсутність стану — основи функціонального програмування, і вкрай важливо їх зрозуміти, але не переживайте, якщо для вас все як і раніше туманно. До кінця статті ви зрозумієте суть цих принципів, і я обіцяю, що краса, акуратність і міць функціонального програмування перетворять ваш код в яскраву, блискучу, гризучий дані веселку. Але поки почнемо з простих функцій, які повертають дані (або інші функції), а потім об'єднаємо їх для виконання більш складних завдань.
 
Наприклад, нехай у нас є деякий відповідь від API:
 
 
var data = [{
    name: "Jamestown",
    population: 2047,
    temperatures: [-34, 67, 101, 87]
}, {
    name: "Awesome Town",
    population: 3568,
    temperatures: [-3, 4, 9, 12]
}, {
    name: "Funky Town",
    population: 1000000,
    temperatures: [75, 75, 75, 75, 75]
}];

Якщо ми хочемо використовувати графічну бібліотеку для зіставлення середньої температури і населення, нам потрібно написати трохи коду, який готує дані до візуалізації. Нехай наша бібліотека для побудови графіків чекає на вхід масив
x
— і
y
-координат зразок такого:
 
 
[
    [x, y],
    [x, y]
    // ... и т.д.
]

де
x
— середня температура, а
y
— населення.
 
Без функціонального програмування (або без його застосування, тобто в імперативний стилі ) наш код виглядав би якось так:
 
 
var coords = [],
    totalTemperature = 0,
    averageTemperature = 0;

for (var i = 0; i < data.length; i++) {
    totalTemperature = 0;

    for (var j = 0; j < data[i].temperatures.length; j++) {
        totalTemperature += data[i].temperatures[j];
    }

    averageTemperature = totalTemperature / data[i].temperatures.length;
    coords.push([averageTemperature, data[i].population]);
}

Навіть у цьому висмоктати з пальця прикладі непросто за все встежити. Що ж, подивимося, як зробити все зрозуміліше.
 
Для функціонального підходу завжди характерний пошук простих, часто повторюваних дій, які можуть бути виділені у функції. Потім можна робити більш складні дії, викликаючи ці функції в певному порядку (що також називається композицією функцій ) — скоро я зупинюся на цьому докладніше. Визначимо, що потрібно зробити, щоб привести вихідні дані в формат, необхідний бібліотекою. Подивившись код краєм ока, можна виділити наступні дії:
 
     
  • додати кожне число в список;
  •  
  • порахувати середнє значення;
  •  
  • витягти кожне властивість зі списку об'єктів.
  •  
Ми напишемо функцію для кожного з цих дій, а потім складемо програму з цих функцій. На початку функціональне програмування може трохи збивати з пантелику, і у вас напевно з'явиться спокуса пащу назад до своїх старих імперативним звичкам. Щоб це не сталося, я приведу нижче список головних правил, що гарантують, що ви прямуєте кращим практикам:
 
     
  • всі ваші функції повинні приймати хоча б один параметр;
  •  
  • всі ваші функції повинні повертати чи дані, або іншу функцію;
  •  
  • ніяких циклів!
  •  
Що ж, почнемо розробку. Крок перший — додамо кожне число в список. Зробимо функцію, приймаючу параметр — масив чисел, і повертає деякі дані.
 
 
function totalForArray(arr) {
    // любой код
    return total;
}

Поки все добре, але… як же нам отримати доступ до кожного елементу списку, якщо ми не можемо циклічно його обійти? Скажіть привіт вашому новому товаришеві — рекурсії! Коли ви використовуєте рекурсію, ви створюєте функцію, яка викликає себе, якщо не виповнилося спеціальна умова виходу — в цьому випадку просто повертається поточне значення. Може бути незрозуміло, але подивіться на цей найпростіший приклад:
 
 
// Обратите внимание, что мы принимаем два значения — список и текущий результат
function totalForArray(currentTotal, arr) {
    currentTotal += arr[0];

    // Заметка для опытных JavaScript-программистов: я не использую Array.shift,
    // потому что в статье мы ведём себя с массивами так, как будто они неизменяемые
    var remainingList = arr.slice(1);

    // Вызываем эту же функцию, передавая остаток (хвост) списка как параметр,
    // а currentTotal — текущее значение
    if (remainingList.length > 0) {
        return totalForArray(currentTotal, remainingList);
    }

    // Конечно, если список не пуст — в этом случае мы просто возвращаем currentTotal
    else {
        return currentTotal;
    }
}

 Обережно: Рекурсія робить код більш легким для читання і природна для програмування у функціональному стилі. Проте, в деяких мовах (включаючи JavaScript) виникнуть проблеми, якщо програма зробить занадто багато рекурсивних викликів (на момент написання статті «занадто багато» — це приблизно 10000 викликів в Chrome, 50000 викликів в Firefox і 11000 викликів в Node.js). Детальний розбір виходить за межі цієї статті, але суть в тому, що принаймні до остаточного релізу ECMAScript 6 JavaScript не підтримуватиме дещо, зване «хвостовій рекурсією» — більш ефективно організовану форму рекурсії. Ця складна і нечасто зустрічається тема, але проте про неї корисно знати.
 
Тепер повернемося до нашого завдання — нам потрібно підрахувати загальну температуру по масиву температур, щоб потім обчислити середню. Тепер замість обходу масиву в циклі ми можемо просто написати:
 
 
var totalTemp = totalForArray(0, temperatures);

Якщо ви перфекціоніст, ви можете заявити, що функцію
totalForArray
теж можна розбити на функції. Наприклад, складання чисел може зустрітися і в інших місцях програми і тому теж має виконуватися окремою функцією.
 
 
function addNumbers(a, b) {
    return a + b;
}

Тепер наша функція
totalForArray
виглядає якось так:
 
 
function totalForArray(currentTotal, arr) {
    currentTotal = addNumbers(currentTotal, arr[0]);
    var remainingArr = arr.slice(1);

    if (remainingArr.length > 0) {
        return totalForArray(currentTotal, remainingArr);
    } else {
        return currentTotal;
    }
}

Чудово! Отримання одного значення по масиву настільки часто зустрічається у функціональному програмуванні, що навіть має власну назву — " згортка " — Ви, може, чули в якості дієслова — щось на кшталт «згорнути список до одного значення». У JavaScript є спеціальний метод для виконання цього завдання. На Mozilla Developer Network є докладний опис , але для нашого завдання поки достатньо прикладу:
 
 
// Функция свёртки принимает первым аргументом некоторую функцию, которая ожидает
// в качестве параметров текущий элемент и текущий результат вычислений
var totalTemp = temperatures.reduce(function(previousValue, currentValue) {
    // После завершения вычисления следующее значение currentValue будет равно previousValue + currentValue,
    // а следующее значение previousValue будет равно следующему элементу массива
    return previousValue + currentValue;
});

Але почекайте-ка, ми ж вже визначили функцію
addNumber
, тому ми можемо використовувати її:
 
 
var totalTemp = temperatures.reduce(addNumbers);

І оскільки згортка така Крутецкая, давайте виділимо її в окрему функцію, щоб ми могли просто викликати її без необхідності пам'ятати всі ці заплутані деталі.
 
 
function totalForArray(arr) {
    return arr.reduce(addNumbers);
}

var totalTemp = totalForArray(temperatures);

О, ось тепер код легко читається! До слова, методи начебто згортки присутні в більшості функціональних мов. Ці допоміжні методи, що виконують дії над списками замість метушні з циклами, називаються функціями вищого порядку .
 
Що ж, рухаємося далі; наступна задача за нашим списком — підрахунок середнього значення. Це дуже просто.
 
 
function average(total, count) {
    return total / count;
}

Як далеко ми зайдемо для підрахунку середнього значення по всьому масиву?
 
 
function averageForArray(arr) {
    return average(totalForArray(arr), arr.length);
}

var averageTemp = averageForArray(temperatures);

Сподіваюся, ви почали розуміти, як працює композиція функцій для виконання більш складних завдань. Все це можливо завдяки дотримання правилам, перерахованим на початку статті, а саме тому, що функції повинні приймати параметри і повертати дані. Зручно ж.
 
Тепер потрібно витягти по одній властивості з кожного об'єкта масиву. Замість того, щоб показувати приклади рекурсії, я зосереджуся на важливому і покажу ще один вбудований в JavaScript метод:
map
. Цей метод потрібен, якщо треба відобразити масив структур одного типу в список структур іншого типу:
 
 
// Метод принимает единственный параметр — функцию, ожидающую параметр,
// равный текущему элементу списка
var allTemperatures = data.map(function(item) {
    return item.temperatures;
});

Все це круто, але витяг властивості з колекції об'єктів — щось, що робиться постійно, тому напишемо функцію і для цього.
 
 
// Параметр — имя свойства, которое нужно получить
function getItem(propertyName) {
    // Возвращаем функцию, которая извлекает значение, но не выполняем её сразу.
    // Вызывать её будет метод, который будет выполнять действия над нашим массивом.
    return function(item) {
        return item[propertyName];
    }
}

Ого, ми написали функцію, яка повертає функцію! Тепер ми можемо передати її в метод
map
:
 
 
var temperatures = data.map(getItem('temperature'));

Якщо ви любите деталі, то поясню: причина, по якій ми можемо це робити, в тому, що в JavaScript функції — «об'єкти першого класу», що означає, що ви можете використовувати функцію так само, як і будь-яке інше значення. Хоча так можна робити в багатьох мовах, це одна з вимог для того, щоб мова могла використовуватися для програмування у функціональному стилі. Між іншим, це також причина, по якій ви можете робити штуки на кшталт
$('#my-element').on('click', function(e) { //... })
. Другий параметр методу
on
— функція, і коли ви передаєте функції як параметри, ви використовуєте їх так само, як використовували б звичайні значення в імперативних мовах. Витончено.
 
Нарешті, обгорнемо виклик методу
map
у власну функцію, щоб зробити більш легким для читання.
 
 
function pluck(arr, propertyName) {
    return arr.map(getItem(propertyName));
}

var allTemperatures = pluck(data, 'temperatures');

Так, тепер у нас є набір узагальнених функцій, які можуть бути використані в будь-якому місці програми та навіть в інших проектах. Ми можемо підраховувати елементи масиву, отримувати середні значення по масиву і створювати нові масиви, витягуючи властивості зі списків об'єктів. Тепер останнє за рахунком, але не за важливістю — повернемося до вихідної задачі:
 
 
var data = [{
    name: "Jamestown",
    population: 2047,
    temperatures: [-34, 67, 101, 87]
  }, {
    // ...
}];

Нам потрібно перетворити масив об'єктів на кшталт того, що вказаний вище, в масив пар
x
,
y
:
 
 
[
    [75, 1000000],
    // ...
];

де
x
— середня температура, а
y
— населення. По-перше, винесемо потрібні нам дані:
 
 
var populations = pluck(data, 'population');
var allTemperatures = pluck(data, 'temperatures');

Тепер порахуємо список середніх значень. Потрібно пам'ятати, що функція, яку ми передаємо в метод
map
, буде викликана для кожного елемента масиву; що повертається переданої функцією значення буде додано в новий масив, і цей новий масив буде присвоєно нашої змінної
averageTemps
.
 
 
var averageTemps = allTemperatures.map(averageForArray);

Поки все OK, але тепер у нас два масиви:
 
 
// populations
[2047, 3568, 1000000]

// averageTemps
[55.25, 5.5, 75]

Але нам же потрібен тільки один масив, так що напишемо функцію для їх об'єднання. Наша функція буде перевіряти, що елемент за індексом 0 з першого масиву складається в парі з елементом за індексом 0 з другого масиву, і так далі для інших індексів з 1 по n (де n — загальна кількість елементів кожного з масивів) [оскільки в чистому JavaScript відсутній
zip
— прим. перекладача].
 
 
function combineArrays(arr1, arr2, finalArr) {
    // Устанавливаем значение по умолчанию
    finalArr = finalArr || [];

    // Добавляем текущий элемент каждого из массивов в результирующий
    finalArr.push([arr1[0], arr2[0]]);

    var remainingArr1 = arr1.slice(1),
    remainingArr2 = arr2.slice(1);

    // Если оба массива пусты, то мы закончили
    if ((remainingArr1.length === 0) && (remainingArr2.length === 0)) {
        return finalArr;
    } else {
        // Рекурсия!
        return combineArrays(remainingArr1, remainingArr2, finalArr);
    }
};

var processed = combineArrays(averageTemps, populations);

Однострочнікі — це весело:
 
 
var processed = combineArrays(pluck(data, 'temperatures').map(averageForArray), pluck(data, 'population'));

// [
//  [ 55.25, 2047 ],
//  [ 5.5, 3568 ],
//  [ 75, 1000000 ]
// ]

 
 

Ближче до життя

Наостанок розглянемо більш близький до реального життя приклад, на цей раз додавши до нашого інструментарію Underscore.js — JavaScript-бібліотеку, яка безліч чудових допоміжних функцій. Ми будемо отримувати дані з CrisisNET — сервісу для збору інформації про зіткнення і катастрофах, і візуалізувати їх за допомогою приголомшливої ​​бібліотеки D3 .
 
Мета полягає в тому, щоб дати відвідувачам CrisisNET картинку про всіх типах інформації, пропонованих сервісом. Для цього ми будемо підраховувати кількість отриманих через API сервісу документів, відповідних деякої категорії (наприклад, «фізичне насильство» або «збройний конфлікт»). Так користувач зможе побачити, як багато інформації доступно з тих тем, які здаються йому найбільш цікавими.
 
Бульбашкова діаграма може бути чудовим варіантом, тому що вони часто використовуються для представлення відносних розмірів великих груп людей. На щастя, D3 підтримує спеціальний тип діаграм, іменований
pack
. Що ж, давайте зробимо такий графік, і нехай він показує кількість разів, яке вказане ім'я категорії з'являється у відповіді від CrisisNET API.
 
Перед тим, як ми почнемо, слід нагадати, що D3 — складна бібліотека, що вимагає окремого вивчення. Оскільки ця стаття присвячена функціональному програмуванню, ми не будемо витрачати час на опис того, як працює D3. Не переживайте — якщо ви ще не знайомі з цією бібліотекою, ви завжди можете скопіпастіть код розібрати його. Самовчитель з D3 Скотта Мюррея — відмінне джерело знань з цієї бібліотеці.
 
Насамперед переконаємося, що у нас є DOM-елемент, в який D3 зможе помістити згенерований за нашими даними графік.
 
 
<div id="bubble-graph"></div>

Тепер створимо нашу діаграму і помістимо її в DOM.
 
 
// ширина диаграммы
var diameter = 960,
    format = d3.format(",d"),
    // Создаёт шкалу с 20 цветами
    color = d3.scale.category20c(),

// Объект диаграммы, в который мы будем помещать данные
var bubble = d3.layout.pack()
    .sort(null)
    .size([diameter, diameter])
    .padding(1.5);

// Добавляем в DOM SVG-объект, который D3 будет использовать для рисования
var svg = d3.select("#bubble-graph").append("svg")
    .attr("width", diameter)
    .attr("height", diameter)
    .attr("class", "bubble");

Об'єкт
pack
приймає масив об'єктів наступного формату:
 
 
{
    children: [{
        className: ,
        package: "cluster",
        value:
    }]
}

CrisisNET API повертає дані наступного формату:
 
 
{
    data: [{
        summary: "Example summary",
        content: "Example content",
        // ...
        tags: [{
            name: "physical-violence",
            confidence: 1
        }]
    }]
}

Ми бачимо, що кожен документ має властивість «тег» (
tag
), і ця властивість містить масив елементів, кожен з яких має властивість
name
, що містить ім'я — воно-то нам і потрібно. Нам доведеться підрахувати кількість того, скільки разів ім'я кожного тега зустрічається в результатах, що повертаються CrisisNET API. Почнемо з того, що винесемо інформацію, яка нам потрібна, використовуючи вже написану функцію
pluck
.
 
 
var tagArrays = pluck(data, 'tags');

Тепер у нас є масив такого формату:
 
 
[
    [{
        name: "physical-violence",
        confidence: 1
    }], [{
        name: "conflict",
        confidence: 1
    }]
]

Але нам потрібен єдиний масив всіх тегів. Хм, скористаємося зручною функцією
flatten
з Underscore.js — вона витягне значення з вкладених масивів і поверне нам один загальний масив без вкладеності.
 
 
var tags = _.flatten(tagArrays);

Що ж, тепер з нашим масивом трохи простіше працювати:
 
 
[{
    name: "physical-violence",
    confidence: 1
}, {
    name: "conflict",
    confidence: 1
}]

Тепер знову скористаємося функцією
pluck
для отримання того, що нам потрібно — простого списку імен тегів.
 
 
var tagNames = pluck(tags, 'name');

[
    "physical-violence",
    "conflict"
]

Так, так набагато краще.
 
Тепер ми займемося щодо прямолінійної завданням — підрахунком кількості разів, яке кожне ім'я тега зустрічається в нашому списку, і перетворенням цього списку в структуру, яка потрібна для побудови діаграми. Як ви могли помітити, масиви вельми популярні у функціональному програмуванні — велика частина інструментів спроектована з розрахунком на масиви [автор часто пише «масиви» («arrays»), але має на увазі, очевидно, списки, що в загальному випадку зовсім не обов'язково одне і те ж — прим. перекладача]. Для початку ми створимо ось такий масив:
 
 
[
  ["physical-violence", 10],
  ["conflict", 27]
]

Тут кожен елемент масиву являє собою масив, в якій нульовий елемент — ім'я тега, а перший елемент — кількість, яка тег зустрічається в результатах. Для початку створимо масив, в якому кожне ім'я тега зустрічається єдиний раз. На щастя, Underscore.js надає метод для цієї мети.
 
 
var tagNamesUnique = _.uniq(tagNames);

Також позбудемося всіх
false
-значний (
false
,
null
,
""
і т.д.)
y
-координати, застосувавши іншу функцію з Underscore.js:

tagNamesUnique = _.compact(tagNamesUnique);

Тепер накатав функцію, яка згенерує наш масив, використовуючи інший вбудований в JavaScript метод —
filter
, який вибирає тільки ті значення, які задовольняють деякій умові.

function makeArrayCount(keys, arr) {
    // Для каждого уникального имени тега
    return keys.map(function(key) {
        return [
            key,
            // Фильтруем по имени тега и возвращаем количество
            arr.filter(function(item) {
                return item === key;
            }).length
        ]
    });
}

Тепер ми легко можемо створити структуру даних, яка потрібна D3 для побудови діаграми
pack
, відобразивши структуру функцією
map
.

var packData = makeArrayCount(tagNamesUnique, tagNames).map(function(tagArray) {
    return {
        className: tagArray[0],
        package: "cluster",
        value: tagArray[1]
    }
});

Нарешті, ми можемо передати ці дані D3 і згенерувати потрібні DOM-елементи в нашому SVG — під одному кружку на кожне ім'я тега з розмірами, пропорційними загальною кількістю раз, яке ім'я цього тега зустрічається у відповіді API CrisisNET.

function setGraphData(data) {
var node = svg.selectAll(".node")
    // Сюда мы передаём наши данные
    .data(bubble.nodes(data)
    .filter(function(d) {
        return !d.children;
    }))
    .enter().append("g")
    .attr("class", "node")
    .attr("transform", function(d) {
        return "translate(" + d.x + "," + d.y + ")";
    });

// Добавляем кружок для каждого имени тега
node.append("circle")
    .attr("r", function(d) {
        return d.r;
    })
    .style("fill", function(d) {
        return color(d.className);
    });

// Добавляем подпись с именем тега к каждому кружку
node.append("text")
    .attr("dy", ".3em")
    .style("text-anchor", "middle")
    .style("font-size", "10px")
    .text(function(d) {
        return d.className
    });
}

Об'єднавши всі разом, ми можемо подивитися роботу функцій
setGraphData
і
makeArray
в загальному контексті, включаючи запит до API CrisisNET за допомогою jQuery (правда, для цього потрібно отримати API-ключ ). Я також розмістив повністю робочий код цього прикладу на GitHub.

function processData(dataResponse) {
    var tagNames = pluck(_.flatten(pluck(dataResponse.data, 'tags')), 'name');
    var tagNamesUnique = _.uniq(tagNames);

    var packData = makeArrayCount(tagNamesUnique, tagNames).map(function(tagArray) {
        return {
            className: tagArray[0],
            package: "cluster",
            value: tagArray[1]
        }
    });

    return packData;
}

function updateGraph(dataResponse) {
    setGraphData(processData(dataResponse));
}

var apikey = // Получить API-ключ можно здесь: http://api.crisis.net
var dataRequest = $.get('http://api.crisis.net/item?limit=100&apikey=' + apikey);

dataRequest.done(updateGraph);

Це було непросте і глибоке занурення, тому залишається тільки привітати із завершенням! Як я говорив раніше, перейнятися представленими ідеями спочатку може бути непросто, однак усіма силами противитися спокусі повернутися до імперативним циклам!

За кілька тижнів використання принципів функціонального програмування ви швидко побудуєте прості, придатні до повторного використання функції, які підвищать удобочитаемость вашого коду. До того ж, ви зможете значно швидше працювати зі структурами, кількома рядками роблячи те, що раніше доводилося напружено налагоджувати по півгодини. А раз ваші дані будуть правильно перетворені, у вас залишиться більше часу на приємну частину — на те, щоб все виглядало шикарно!

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.