В предыдущем посте о функциональном программировании мы видели некоторые преимущества, которые дает нам эта парадигма программирования, мы также могли видеть некоторые преимущества по сравнению с объектно-ориентированным программированием, на этот раз мы немного узнаем о фокусе функций в рамках функционального программирования через первый функции класса и чистые функции. Если вам нравится этот контент, вы можете поставить мне лайк или оставить комментарий.
Функции первого класса
В функциональном программировании функции являются гражданами первого класса, что означает, что с ними можно обращаться как со строками, логическими значениями, числами и т. д. Таким образом, функции могут быть переданы в качестве параметров другим функциям, сохранены в массивах, в переменных, во всем, что вы делаете с обычными данными.
Однако очень часто можно найти очень плохие примеры функций первого класса, например следующие:
const print = param => console.log(param)
В этом случае совершенно не нужно создавать еще одну функцию, которая принимает тот же параметр и выполняет то же действие, это было бы проще сделать следующим образом:
const print = console.log
Поскольку console.log — это функция, мы должны назначить ее другой переменной без необходимости создавать другую функцию, так как она, очевидно, более подробная и задерживает оценку, поскольку это функции, которые без необходимости выполняют другие функции.
Очень важно понять это, прежде чем продолжить, поэтому важно просмотреть несколько примеров, чтобы убедиться, что мы поняли:
// ignorant const getData = callback => ajax(callback) // enlightened const getData = ajax;
Давайте посмотрим на другой пример, который позволит нам легче проверить, почему я так настойчив:
const ProductController = { index(product) { return Views.index(product); }, show(product) { return Views.show(product); }, create(attrs) { return Db.create(attrs); }, update(product, attrs) { return Db.update(product, attrs); }, destroy(product) { return Db.destroy(product); }, };
Практически мы могли бы полностью переписать этот контроллер как:
const ProductController = { index: Views.index show: Views.show create: Db.create update: Db.update delete: Db.delete };
Важность первоклассных функций
Основная причина использования первоклассных функций — это простота чтения нашего кода, потому что мы удаляем весь ненужный код, который мешает чтению нашего кода, представьте, что у нас есть функция, которая делает запрос к адресу, который принимает в качестве первого параметра и к полученным данным применяется функция, которая получает в качестве второго параметра:
httpGet(‘/product/1232’, (json,error) => renderProduct(json,error));
Было бы намного легче читать, если бы мы сделали это так:
httpGet(‘/product/1232’, renderProduct);
При создании функций мы также должны создавать функции с максимально общими именами, чтобы иметь возможность повторно использовать их позже в другом случае. Пример:
// specific to our current product const validProduct = products => products.filter(product => product !== null && product !== undefined); // vastly more relevant for future projects const general = xs => xs.filter(x => x !== null && x !== undefined);
Чистые функции в глубине
Чистые функции никогда не должны изменять какое-либо значение за пределами своей области, поэтому они должны всегда возвращать одно и то же значение для данного ввода, ярким примером этого может быть метод среза, который, в отличие от сплайсинга, всегда возвращает один и тот же результат для одних и тех же параметров.
const arr = [1,2,3,4,5]; // pure console.log(arr.slice(0,3)); // [1,2,3] console.log(arr.slice(0,3)); // [1,2,3] console.log(arr.slice(0,3)); // [1,2,3] // impure console.log(arr.splice(0,3)); // [1,2,3] console.log(arr.splice(0,3)); // [4,5] console.log(arr.splice(0,3)); // []
В функциональном программировании по возможности избегают таких функций, как склейка, которые изменяют данные. Поэтому наши функции никогда не должны зависеть от изменяемых значений или внешних переменных. Давайте посмотрим на другой пример:
// impure let minAge = 18; const isAdult = age => age >= minAge; // pure const isAdult = (age) => { const minAge = 18; return age >= minAge; };
Здесь мы видим, что в чистой форме написания нашей функции мы устраняем зависимость глобального состояния, а также устанавливаем константу для переменной minAge, чтобы избежать изменения ее значения.
Побочные эффекты
Побочным эффектом является изменение глобального состояния. Побочные эффекты считаются основной причиной ошибок и нежелательного поведения в нашем коде, поэтому их необходимо уменьшить и строго контролировать, поскольку не все эффекты плохи, но они являются средой, в которой может возникнуть много ошибок. Бывают случаи, когда побочные эффекты обязательны, но мы узнаем об этом, когда будем рассматривать функторы и монады.
Математические функции
Итак, как я упоминал в предыдущем посте, функциональное программирование основано на математических функциях, а математические функции можно определить как отношения между двумя значениями: входом и выходом. Необходимо уточнить, что один и тот же результат можно получить с несколькими входами, но никогда нельзя получить несколько выходов для одного и того же входа.
В следующем примере показана допустимая функция:
В следующем примере показана недопустимая функция:
Преимущества чистых функций
Их можно сохранить: чистые функции могут хранить выходные данные уже использованных входных данных с помощью метода, называемого мемоизацией, давайте рассмотрим простой пример.
const memoize = (f) => { const cache = {}; return (...args) => { const argStr = JSON.stringify(args); cache[argStr] = cache[argStr] || f(...args); return cache[argStr]; }; }; const square = memoize(x => x * x); square(4); // 16 square(4); // 16, returns cache for input 4 square(5); // 25 square(5); // 25, returns cache for input 5
Самодокументированные чистые функции являются автономными. Все их требования получены через их параметры. Вам может быть интересно, как это выгодно, это выгодно, потому что очень легко увидеть его зависимости и понять, как это работает, давайте посмотрим на пример:
// impure const list=[1,2,3,4] const printList = () => { list.forEach(e=>console.log(e)) }; // pure const printList = (list) => { list.forEach(e=>console.log(e)) };
Тестируемость: чистые функции очень легко тестировать, что помогает нам значительно сократить время тестирования нашего приложения.
На сегодня это все в следующем посте Посмотрим о карри и сочинении. Увидимся завтра.
Спасибо за чтение, следуйте за мной, чтобы узнать больше