Подробное объяснение Functor в функциональном программировании

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

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

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

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

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

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

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

Давайте продемонстрируем здесь функтор через код. Функтор — это обычный объект, который поддерживает значение и предоставляет метод отображения для внешнего мира, поэтому мы можем описать функтор через класс, потому что функтор — это контейнер, имя нашего класса здесь называется Контейнер.

class Container {
    map () {
    }
}

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

Мы согласны с тем, что все члены, начинающиеся со знака подчеркивания, являются закрытыми членами, поэтому мы используем this._value для получения здесь.

class Container {
    constructor(value) {
        this._value = value;
    }

    map () {
    }
}

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

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

Затем при возврате нового функтора нам нужно передать обработанное значение в Container, так что это fn(this._value)

class Container {
    constructor(value) {
        this._value = value;
    }

    map (fn) {
        return new Container(fn(this._value));
    }
}

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

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

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

const r = new Container(5).map(x => x + 1);

console.log(r);

Здесь r — объект-контейнер, а значение _value в объекте равно 6. Наш метод карты возвращает не значение, а новый объект функтора. Мы храним новые значения в новом объекте функтора. Мы никогда не публикуем значение во внешний мир. Если мы хотим обработать значение, мы отдаем его объект карты. Передайте функцию, которая обрабатывает значение.

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

Чтобы отличить его от объектно-ориентированного, мы не используем new для создания функторов. Мы можем создать статический метод в Container. Функция этого метода — возвращать объект функтора. При создании объекта функтора нам нужно передать значение, поэтому метод of получает значение и передает его объекту.

class Container {
    static of (value) {
        return new Container(value);
    }

    constructor(value) {
        this._value = value;
    }

    map (fn) {
        return Container.of(fn(this._value));
    }
}

let r = Container.of(5);

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

Functor - это метод карты объекта, в письме Son для сохранения значения, которое никогда не публиковалось, поскольку это значение завернуто в коробку внутри, мы хотим иметь дело с этим значением, мы будем вызывать метод карты. метод map возвращает новый функтор, который позже выполняется.

FunctorСводка

Операции функционального программирования не работают со значениями напрямую, а выполняются функторами. Функтор — это объект, реализующий контракт карты, то есть все функторы имеют объект карты.

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

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

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

Есть проблема с функтором, который мы написали выше, если мы передадим null при создании функтора, например, при сетевом запросе данные не будут получены, при выполнении метода map может быть сообщено об ошибке, что сделает наша функция становится нечистой.

Поскольку Pure Function требует ввода и вывода, а при прохождении NULL функция не выводится в это время, фактически передается нулевые побочные эффекты, то мы должны найти способ решить эту проблему, которая представляет собой контрольные побочные эффекты.

Функтор MayBe

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

Мы можем столкнуться со многими ошибками в процессе программирования, с этими ошибками нам нужно работать, функция функтора MayBe состоит в том, чтобы работать с внешним нулевым значением.

Мы можем думать о внешней передаче нулевого значения как о побочном эффекте, и функтор MayBe может управлять этим побочным эффектом. Давайте продемонстрируем функтор MayBe.

Сначала мы создаем класс MayBe,

class MayBe {
    static of (value) {
        return new MayBe(value)
    }
    constructor (value) {
        this._value = value;
    }
    map (fn) {
        return MayBe.of(fn(this._value)); 
    }
}

class MayBe {
    static of (value) {
        return new MayBe(value)
    }
    constructor (value) {
        this._value = value;
    }
    map (fn) {
        return MayBe.of(fn(this._value)); 
    }
    isNothing () {
        return ths._value === null || this._value === undefined;
    }
}

Затем в методе карты, перед выполнением fn, нам нужно определить, является ли this._value пустым.Если текущее значение пусто, мы не можем вызвать fn.Мы должны вернуть функтор со значением null, если есть значение We снова вызовите fn, здесь мы используем троичное выражение.

class MayBe {
    static of (value) {
        return new MayBe(value)
    }
    constructor (value) {
        this._value = value;
    }
    map (fn) {
        return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this._value)); 
    }
    isNothing () {
        return ths._value === null || this._value === undefined;
    }
}

На этом этапе, если мы передадим null, наш код не сообщит об ошибке, а вернет новый функтор MayBe со значением null.

Далее, давайте рассмотрим проблему с функтором MayBe.Хотя мы можем справиться с проблемой нулевых значений, если мы вызовем метод карты несколько раз, мы не уверены, в какой момент появляется нулевое значение.

Либо функтор

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

Когда мы раньше использовали функтор MayBe, когда мы передавали null, мы не имели бы дело с внешней функцией fn, а просто возвращали бы функтор со значением null, но он не давал бы никакой достоверной информации, он не скажет нам, что пошло не так и что пошло не так.

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

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

Когда мы используем функтор либо, поскольку он выбирает один из двух, нам нужно определить два типа, один — левый, а другой — правый, в этих двух классах мы должны определить статический метод, чтобы вернуть его обратно в класс. текущий Этот объект, а также конструктор и метод карты.

В методе карты Left он здесь особенный, который напрямую возвращает this, а метод карты Right такой же, как и раньше.

class Left {
    static of (value) {
        return new Left(value);
    }
    constructor (value) {
        this._value = value;
    }
    map (fn) {
        return this;
    }
}
 
class Right {
    static of (value) {
        return new Right(value);
    }
    constructor (value) {
        this._value = value;
    }
    map (fn) {
        return Right.of(fn(this._value));
    }
}

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

let r1 = Right.of(12).map( x => x + 2);
let r12 = Left.of(12).map( x => x + 2);

console.log(r1); // ...14
console.log(r2); // ...12

Здесь мы услышали функторы, созданные путем печати Left и Right, и мы можем обнаружить, что Left возвращает значение, которое мы передали напрямую, без какой-либо обработки. Метод карты в Left — это текущий объект, который напрямую возвращается, и не вызывает текущий объект, переданный в fn.

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

Поскольку исключения могут возникнуть при звонке json.parse, мы используем попробуйте ... catch. Если возникает исключение, и мы не обрабатываем его, это не чистая функция. Теперь мы хотим обрабатывать его функциональным способом, поэтому нам нужна чистая функция.

Если есть ошибка, мы также возвращаем значение в улове, потому что чистая функция должна иметь вывод.На данный момент мы также хотим вернуть функтор, а Left in Both используется для обработки исключений.

function parseJSON (str) {
    try {
        return Right.of(JSON.parse(str));
    } cache (e) {
        return Left.of({
            error: e.message
        })
    }
}

Таким образом, наш parseJSON закончен, и это обработка исключений в Both.

IO-функтор

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

Далее давайте узнаем о функторе ввода-вывода, который является функтором ввода и вывода.Разница между ним и предыдущим функтором заключается в том, что его внутреннее значение всегда является функцией.

Функтор IO хранит все нечистые операции в значении, а значение хранит функцию.Эта функция не вызывается внутри функтора.Функтор IO задерживает выполнение этих нечистых операций, что эквивалентно ленивому выполнению.

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

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

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

Через метод OF мы видим, что корреспондент IO все еще захочет вернуть данные, только здесь IO, значение IO, сохраните эту функцию. Эта функция возвращает значение, он задерживает процесс оценки значения.Когда мы хотим это значение, вызываем функцию Значение функции ввода-вывода.

Метод карты здесь также отличается от предыдущего. Корейский стиль карты получает функцию fn. В методе карты функтор ввода-вывода создается путем вызова конструктора ввода-вывода. Параметр вызывает flowRight fp для объединения fn и значения. Наконец, новая функция передается конструктору ввода-вывода, получается функтор ввода-вывода и он возвращается.

const  fp = require('lodash/fp');

class IO {
    static of (x) {
        return new IO(function() {
            return x;
        })
    }
    consturctor (fn) {
        this._value = fn;
    }
    map (fn) {
        return new IO(fp.flowRight(fn, this._value));
    }
}

Сначала мы вызываем метод of IO, чтобы вернуть функтор, метод of получает значение, и мы можем передать процесс (только в среде Node).

Затем мы вызываем метод карты, чтобы получить exePath в процессе, который является путем выполнения процесса в среде текущего узла.

let r = IO.of(process).map(p => p.execPath);

console.log(r);

Можно обнаружить, что то, что мы возвращаем здесь, является функтором ввода-вывода. Значение в этом функторе ввода-вывода хранит функцию function. Давайте проанализируем, кто эта функция.

Когда мы вызываем IO.of, мы передаем объект процесса, в of мы возвращаем функтор и оборачиваем процесс в функцию, затем вызываем метод карты и вызываем flowRight в методе карты, чтобы объединить функции, которые оборачивают процесс. in of Функция передается на карту. Возвращает функтор ввода-вывода.

Эта функция является текущим значением, которое является функтором функций после комбинации.

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

let r = IO.of(process).map(p => p.execPath);

console.log(r._value());

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

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

Монадный функтор

Перед изучением Monad является следующий вопрос, который мы впервые IO Fanctor, есть команда CAT в системе Linux, прочитала содержимое файла и распечатайте его ему, мы пишем функцию для моделирования этой команды.

class IO {
    static of (x) {
        return new IO(function() {
            return x;
        })
    }
    consturctor (fn) {
        this._value = fn;
    }
    map (fn) {
        return new IO(fp.flowRight(fn, this._value));
    }
}

В функции печати мы также возвращаем функтор ввода-вывода, отложенное выполнение

let readFile = function (filename) {
    return new IO(function () {
        return fs.readFileSync(filename, 'utf-8');
    })
}

let print = function (x) {
    return new IO(function () {
        console.log(x);
        return x;
    })
}

Ниже мы объединяем эти две функции в cat.

let cat = fp.flowRight(print, readFile);

let r = cat('package.json');
 
console.log(r);

После вызова здесь мы readFile возвращает функтор ввода-вывода. После того, как функтор ввода-вывода передается функции печати, эта функция возвращает функтор. Значение в функторе является функтором readFile, поэтому здесь мы получаем вложенную функцию son .

Далее давайте выполним функции в функторе, который мы представили ранее, можно выполнить, вызвав _value().

console.log(r._value());

Когда мы выполняем _value, мы получаем функтор ввода-вывода, возвращаемый функцией readFile, потому что возвращаемое значение readFile будет передано функции печати.

Теперь мы хотим получить результат файла, нам нужно снова вызвать метод _value, этот метод является _value в readFile

console.log(r._value()._value());

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

Давайте представим Monad для решения вышеуказанной проблемы.

Монада это Pointed функтор который можно сплющить.Что такое сплющивание?У нас есть проблема выше,то есть если функтор вложенный то нам будет очень неудобно вызывать.Сглаживание это решение проблемы вложенности функторов.

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

Если у потомка есть и соединение, и функция двух методов, и он следует какому-то закону, то он является Монадой.

из нас знакомы, присоединиться не сложно, он вернулся непосредственно к нашему вызову _value.

Мы будем трансформироваться в класс IO Monad, добавьте методы соединения, метод join не требует никаких параметров, здесь возвращается к вызову _value.

class IO {
    static of (x) {
        return new IO(function() {
            return x;
        })
    }
    consturctor (fn) {
        this._value = fn;
    }
    map (fn) {
        return new IO(fp.flowRight(fn, this._value));
    }
    join () {
        return this._value();
    }
}

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

class IO {
    static of (x) {
        return new IO(function() {
            return x;
        })
    }
    consturctor (fn) {
        this._value = fn;
    }
    map (fn) {
        return new IO(fp.flowRight(fn, this._value));
    }
    join () {
        return this._value();
    }
    flatMap(fn) {
        return this.map(fn).join();
    }
}

Пока с Монадой покончено, давайте посмотрим, как ее использовать.

let r = readFile('package.json');

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

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

let r = readFile('package.json').flatMap(print);

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

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

То, что возвращает flatMap, — это функтор print, и, наконец, мы хотим получить содержимое файла print, мы можем снова вызвать join, потому что join — это значение внутри вызова.

let r = readFile('package.json').flatMap(print).join();

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

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

Функтор задачи

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

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

Folktale - это стандартная библиотека функционального программирования. В отличие от lodash и ramda, она не предоставляет много функциональных функций. Она предоставляет только операции, связанные с функциональной обработкой, такие как компоновка, карри и т. д. Он также предоставляет некоторые функторы, такие как Task, Eight, Может быть и др.

Давайте сначала продемонстрируем, как использовать compose и curry в сказке.

const { curry } = require('folktale/core/lambda');

let f = curry(2, (x, y) => {
    return x + y;
});

console.log(f(1, 2));

Между curry и lodash есть разница.Он принимает два параметра.Первый параметр используется, чтобы указать, сколько параметров имеет параметр функции. В документации сказано, что цель передачи здесь первого параметра — избежать некоторых ошибок.

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

const { compose } = require('folktale/core/lambda');
const { toUpper, first } = require('lodash/fp');

let f = compose(toUpper, first)

console.log(f(['a', 'b']));

Функция компоновки здесь такая же, как и у flowRight в lodash.

Далее мы представляем заданный функтор, предусмотренный в TalledTale для обработки асинхронных задач. Задача в Folktale2.x очень отличается от задачи в Folktale1.x. Использование в 1.x ближе к использованию функтора, и мы используем 2.x, чтобы продемонстрировать здесь. Это не что иное, как разница в API, мы можем понять использование, консультируя документацию.

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

Представленная здесь задача имеет форму функции, которая возвращает объект функтора, который является классом, представленным в 1.x.

Затем мы пишем функцию для чтения файла readFile, эта функция принимает параметр пути к файлу и возвращает функтор задачи.

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

const { task } = require('folktale/concurrency/task');
const fs = require('fs');

function readFile(filename) {
    return task(resolver => {
        fs.readFile(filename, 'utf-8', (err, data) => {
            if (err) {
                resolver.reject(err);
            } else {
                resolver.resolve(data)
            }
        })
    })
}

readFile('package.json').run();

Мы можем прослушивать статус чтения файла с помощью метода Listen, здесь входящий объект, включая обратный вызов Onrejected и обратный вызов onResolved.

readFile('package.json').run().listen({
    onRejected: err => {
        console.log(err);
    },
    onResolved: value => {
        console.log(value);
    }
})

В этот момент, когда мы снова выполним код, мы обнаружим, что файл был прочитан.Если мы хотим обработать полученное значение, мы можем вызвать метод map функтора Task перед запуском, и мы можем обработать его в метод карты результат. Это больше соответствует функциональному программированию.

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

readFile('package.json').map(value => {
    console.log(value); // 处理文件
    retrun value;
}).run().listen({
    onRejected: err => {
        console.log(err);
    },
    onResolved: value => {
        console.log(value);
    }
})

Остроконечный функтор

Указанные функторы относятся к функторам, которые реализуют статический метод of.Все функторы, которые мы написали ранее, реализуют метод of, поэтому все они являются точечными функторами.

Я сказал, что метод of предназначен для того, чтобы избежать использования new для создания объектов и чтобы наш код не выглядел слишком объектно-ориентированным, но более глубокое значение метода of заключается в том, что он используется для помещения значения в контекст, а затем обработки. нас в контексте значение . (Поместите значение в контейнер, используйте карту для обработки значения).

Предположим, что наше значение равно 2, мы можем поместить это значение в поле через метод of, затем это поле мы называем контекстом, который на самом деле является нашим функтором.

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

Когда мы вызываем, когда мы получаем метод контекста, чтобы иметь дело с будущими нашими данными в этом контексте.

Это заправленная переписка, он относительно простой, это концепция, мы уже использовали его.

Суммировать

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

  • Знакомство с функциональным программированием

Это концепция функционального программирования.

Функциональное программирование — это парадигма программирования или идея программирования. Оно находится на том же уровне, что и объектно-ориентированное программирование. Нам требуется много времени, чтобы овладеть идеей программирования. Мы можем внедрить то, что освоили, непосредственно в нашу работу. вам не нужно писать все функционально, потому что это кажется слишком сложным.

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

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

  • Функциональный обзор

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

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

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

lodash — это библиотека функционального программирования, которая предоставляет множество методов функционального программирования, помогающих нам в разработке.

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

After we understand the pipeline for our learning function combination is helpful, we can put a function imagine a pipeline data processing, we give this piped input data when this data through the pipeline then will get a corresponding result, in fact, this combination of functions иметь дело с.函数组合可以把多个一元的函数组合成一个新的函数,组合成一个功能更强大的函数。

  • Функтор

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

Метод карты получает параметр функционального типа, а функция, которую мы передаем, — это функция для обработки значения.

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

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

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

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