Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

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

Лекция



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

Пожалуйста, читайте вдумчиво и неторопясь. Перед тем, как двигаться дальше, убедитесь, что вы все поняли. Каждая следующая часть главы отталкивается от предыдущей. Если вы будете спешить, то наверняка упустите некоторые нюансы, которые могут быть важны в дальнейшем.

Рефакторинг

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

Вспомним что такое рефакторинг. Вот пример JavaScript-кода:

function validateSsn(ssn) {
    if (/^\d{3}-\d{2}-\d{4}$/.exec(ssn))
        console.log('Valid SSN');
    else
        console.log('Invalid SSN');
}function validatePhone(phone) {
    if (/^\(\d{3}\)\d{3}-\d{4}$/.exec(phone))
        console.log('Valid Phone Number');
    else
        console.log('Invalid Phone Number');
}

Мы все писали такой код и лишь потом начинали понимать, что эти две функции практически одинаковые и отличаются только несколькими моментами (выделены жирным шрифтом).

Вместо копирования validateSsn и последующим ее редактированием для получения validatePhone, нам лучше создать отдельную функцию и параметризировать данные.

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

Код после рефакторинга:

function validateValue(value, regex, type) {
    if (regex.exec(value))
        console.log('Valid ' + type);
    else
        console.log('Invalid ' + type);
}

Параметры ssn и phone из старого примера теперь представлены как value.

Регулярные выражения /^\d{3}-\d{2}-\d{4}$/ и /^\(\d{3}\)\d{3}-\d{4}$/ – как regex.

И наконец, последние части сообщения 'SSN' и 'Phone Number' – как type.

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

Для примера: если возникает ошибка, вам нужно исправить ее в одном-единственном месте в сравнении с тем, чтобы искать по всему исходному коду, куда эта функция МОГЛА БЫТЬ вставлена и переделана.

Но что происходит, когда у нас появляется следующая ситуация:

function validateAddress(address) {
    if (parseAddress(address))
        console.log('Valid Address');
    else
        console.log('Invalid Address');
}function validateName(name) {
    if (parseFullName(name))
        console.log('Valid Name');
    else
        console.log('Invalid Name');
}

Здесь parseAddress и parseFullName – функции, принимающие строку и возвращающие true, если она парсится.

Как произвести рефакторинг в этом случае?

Что ж, мы можем использовать value для adress и name и type для 'Address' и 'Name', как мы делали это раньше, но вместо регулярного выражения здесь функция.

Единственный выход — передавать функцию параметром…

функции высшего порядка

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

Многие языки не поддерживают передачу функций в качестве параметров. Об этом говорит сайт https://intellect.icu . Некоторые — поддерживают, но проще от этого не становится.

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

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

Хотя JavaScript — это не чистый функциональный язык, вы можете выполнять с помощью него некоторые функциональные операции. Вот последние две функции, преобразованные в одну отдельную с помощью передачи функции-парсера в качестве параметра, называющегося parseFunc.

function validateValueWithFunc(value, parseFunc, type) {
    if (parseFunc(value))
        console.log('Valid ' + type);
    else
        console.log('Invalid ' + type);
}

Наша новая функция называется функцией высшего порядка.

Функции высшего порядка либо принимают функции как параметры, либо возвращают их, либо и то, и другое одновременно.

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

validateValueWithFunc('123-45-6789', /^\d{3}-\d{2}-\d{4}$/.exec, 'SSN');
validateValueWithFunc('(123)456-7890', /^\(\d{3}\)\d{3}-\d{4}$/.exec, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');

Это гораздо лучше, чем иметь четыре практически идентичных функций.

Но обратите внимание на регулярные выражения. Они немного пространные. Давайте приведем наш код в порядок, реорганизовав его таким образом:

var parseSsn = /^\d{3}-\d{2}-\d{4}$/.exec;
var parsePhone = /^\(\d{3}\)\d{3}-\d{4}$/.exec;validateValueWithFunc('123-45-6789', parseSsn, 'SSN');
validateValueWithFunc('(123)456-7890', parsePhone, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');

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

Но представьте, что у нас гораздо больше регулярных выражений для парсинга, а не только parseSsn и parsePhone. Каждый раз, когда мы создаем парсер регулярным выражением, мы должны помнить о том, чтобы добавить .exec в конце. И уж поверьте мне, это легко забыть.

Мы можем застраховаться от этого, создав функцию высшего порядка, возвращающую метод exec.

function makeRegexParser(regex) {
    return regex.exec;
}var parseSsn = makeRegexParser(/^\d{3}-\d{2}-\d{4}$/);
var parsePhone = makeRegexParser(/^\(\d{3}\)\d{3}-\d{4}$/);validateValueWithFunc('123-45-6789', parseSsn, 'SSN');
validateValueWithFunc('(123)456-7890', parsePhone, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');

В этом примере makeRegexParser принимает регулярное выражение и возвращает метод exec, который в свою очередь принимает строку. validateValueWithFunc будет передавать строку, value, методу-парсеру, то есть exec.

parseSsn и parsePhone эффективны также, как и раньше, и также, как и метод exec регулярных выражений.

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

Несмотря на это, вы можете представить пользу от подобных изменений, если бы makeRegexParser была гораздо более комплексной.

Вот другой пример функции высшего порядка, возвращающей функцию:

function makeAdder(constantValue) {
    return function adder(value) {
        return constantValue + value;
    };
}

Здесь у нас есть makeAdder, принимающая constantValue и возвращающая adder - функцию, которая будет добавлять значение-константу к любой переданной ей переменной.

Вот как ее можно использовать:

var add10 = makeAdder(10);
console.log(add10(20)); // печатает 30
console.log(add10(30)); // печатает 40
console.log(add10(40)); // печатает 50

Мы создаем функцию, add10, передавая константу 10 функции makeAdder, которая возвращает функцию, которая в свою очередь будет добавлять 10.

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

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

А называется оно замыканием.

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

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

Вот специально придуманный пример функций, использующих замыкание:

function grandParent(g1, g2) {
    var g3 = 3;
    return function parent(p1, p2) {
        var p3 = 33;
        return function child(c1, c2) {
            var c3 = 333;
            return g1 + g2 + g3 + p1 + p2 + p3 + c1 + c2 + c3;
        };
    };
}

В этом примере child имеет доступ к своим локальным переменным, к переменным parent и к переменным grandParent.

parent имеет доступ к своим переменным и к переменным grandParent.

grandParent имеет доступ только к своим переменным.

(Смотрите на пирамиду выше для ясности.)

Вот пример использования всего этого:

var parentFunc = grandParent(1, 2); // возвращает parent()
var childFunc = parentFunc(11, 22); // возвращает child()
console.log(childFunc(111, 222)); // печатает 738
// 1 + 2 + 3 + 11 + 22 + 33 + 111 + 222 + 333 == 738

Здесь parentFunc хранит область видимости parent, потому что grandParent возвращает parent.

Таким же образом childFunc хранит область видимости child, потому что parentFunc, по сути являющийся parent, возвращает child.

Когда создана функция, все переменные в ее области видимости в момент создания доступны ей на время жизни. Функция существует, пока на нее есть ссылка. Для примера, область видимости child существует, пока childFunc продолжает ссылаться на нее.

Замыкание — область видимости функции, которая сохраняется благодаря ссылке на эту функцию.

Обратите внимание, что замыкания в JavaScript — сомнительное удовольствие из-за изменяемости переменных, то есть из-за того, что они могут менять свое значение с момента определения и до тех пор, пока вызываемая функция не возвратится.

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

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

создано: 2020-08-12
обновлено: 2021-03-13
132265



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей



Комментарии


Оставить комментарий
Если у вас есть какое-либо предложение, идея, благодарность или комментарий, не стесняйтесь писать. Мы очень ценим отзывы и рады услышать ваше мнение.
To reply

Функциональное программирование

Термины: Функциональное программирование