Don’ т бояться функционального программирования

Функциональное программирование является усатый хипстеров парадигм программирования.

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

Строгие функциональные языки программирования, как правило, используется, когда производительность и целостность системы являются критически — т.е. ваша программа должна делать то, что вы ожидаете в любое время и должен работать в условиях, когда его задачи могут быть распределены по сотням или тысячам сетевыхкомпьютеры. Clojure 1 , например, полномочия Akamai 2 , массивная сеть доставки контента используется такими компаниями, как Facebook, в то время как Twitter лихо adopted 3 Scala 4 за большинство компонентов сокращает производительность, и Haskell 5 используется AT& T для его сетевой безопасностиСистемы .

Эти языки имеют крутой кривой обучения для большинства интерфейсных веб-разработчиков;Однако, многие более доступным языки конструктивные особенности функционального программирования, особенно Python, как в ее основной библиотеки, с функциями, как map и reduce (который мы будем говорить о в немного), а также с библиотеками, такими как Fn.py 6 вместе с JavaScript, снова используя методы сбора, но и с библиотеками, такими как Underscore.js 7 и Bacon.js 8 .

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

Поиск последовательное определение функционального программирования является жестким, и большая часть литературы опирается на несколько предчувствие заявления, как “функции как объекты первого класса» и «устранение побочных эффектов.” На всякий случай, не сгибать ваш мозг вузлы, на более теоретическом уровне, функциональное программирование часто объясняется в терминах лямбда calculus 9 (некоторые фактически argue 10 , что функциональное программирование в основном по математике), — но вы можете расслабиться.С более прагматичной точки зрения, начинающий должен понимать только два понятия для того, чтобы использовать его для ежедневного применения (не требуется исчисление!) .

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

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

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

Например,давайте, у нас есть ответ 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]
  …etc
]

Здесь 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]);
}

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

При программировании в функциональном стиле, вы всегда ищете простой, повторяемых действий, которые могут быть абстрагированы в функции.Мы можем построить более сложные функции, вызывая эти функции в последовательности (также известные как “составляющих” функций) — подробнее об этом в секунду.В то же время, давайте посмотрим на те шаги мы берем в процессе преобразования исходного ответа API относительно структуры, необходимой нашей библиотеке визуализации.На базовом уровне, мы выполним следующие действия на нашем данных:

  • Добавить каждое число в списке,
  • Расчета в среднем,
  • Получить одно свойство из списка объектов .

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

  1. Все из ваших функций должны принять по крайней мере один аргумент .
  2. Все из ваших функций должны возвращать данные или иная функция .
  3. Нет петли

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

function totalForArray(arr) {
  // add everything
  return total;  
}

Пока все хорошо.Но как мы собираемся открыть каждый пункт в списке, если мы не петлю над ним?Привет вашей новой знакомой, рекурсия!Это немного сложнее, но в основном, когда вы используете рекурсию, вы создаете функцию, которая называет себя, если конкретное условие не было выполнено — в этом случае, значение возвращается.Просто глядя на пример, вероятно, самый простой:

// Notice we're accepting two values, the list and the current total
function totalForArray(currentTotal, arr) {
  
  currentTotal += arr[0]; 

  // Note to experienced JavaScript programmers, I'm not using Array.shift on 
  // purpose because we're treating arrays as if they are immutable.
  var remainingList = arr.slice(1);

  // This function calls itself with the remainder of the list, and the 
  // current value of the currentTotal variable
  if(remainingList.length > 0) {
    return totalForArray(currentTotal, remainingList); 
  }
  
  // Unless of course the list is empty, in which case we can just return
  // the currentTotal value.
  else {
    return currentTotal;
  }
}

Слово предостережения: Рекурсия сделает ваши программы более читаемым, и очень важно, чтобы Программирование в функциональном стиле.Тем не менее, в некоторых языках (в том числе JavaScript), вы столкнетесь с проблемами, когда ваша программа делает большое количество рекурсивных вызовов в рамках одной операции (на момент написания “большой” о 10000 звонков в Chrome, 50000В Firefox и 11000 в Node.js 12 ).Подробности выходят за рамки данной статьи, но суть в том, что, по крайней мере до ECMAScript 6 не released 13 , JavaScript браузер не поддерживает то, что называется “ хвост recursion 14 “, которое является более эффективной формой рекурсии.Это сложная тема, и не будет придумать очень часто, но это стоит знать .

При том, что, кстати, помните, что мы должны были рассчитать общую температуру из массива температур, чтобы потом рассчитать среднее значение.Теперь, вместо того, чтобы цикл по каждому пункту в temperatures массиве, мы можем просто написать так:

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 Сеть разработчиков обеспечивает полный explanation 15 , но для наших целей это так просто, как это:

// The reduce method takes a function as its first argument, and that function 
// accepts both the current item in the list and the current total result from 
// whatever calculation you're performing.
var totalTemp = temperatures.reduce(function(previousValue, currentValue){
  // After this calculation is returned, the next currentValue will be 
  // previousValue + currentValue, and the next previousValue will be the 
  // next item in the array.
  return previousValue + currentValue;
});

Но, эй, так как мы уже определили addNumber функцию, мы можем просто использовать, что вместо .

var totalTemp = temperatures.reduce(addNumbers);

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

function totalForArray(arr) {
  return arr.reduce(addNumbers);
}

var totalTemp = totalForArray(temperatures);

Ах, теперь that некоторые читаемый код!Точно так же вы знаете, методы, такие как reduce являются общими в большинстве функциональных языков программирования.Эти вспомогательные методы, которые выполняют действия над массивами вместо зацикливания часто называют “ функции высшего порядка .”

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

function average(total, count) {
  return total / count;
}

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

function averageForArray(arr) {
  return average(totalForArray(arr), arr.length);
}

var averageTemp = averageForArray(temperatures);

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

Наконец, мы хотелиполучить одно свойство из массива объектов.Вместо того чтобы показывать вам больше примеров рекурсии, я в погоню и ключ вам о другой встроенный метод JavaScript: map 16 .Этот метод, когда у вас есть массив с одной структуре и нужно сопоставить ее с другой структурой, например, так:

// The map method takes a single argument, the current item in the list. Check
// out the link above for more complete examples.
var allTemperatures = data.map(function(item) {
  return item.temperatures;
});

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

// Pass in the name  ... 

Если вы хотите прочитать полностью статью, посетите сайт наших спонсоров

Comments are closed.