Монады в JavaScript

Поэтому я хочу понять практические случаи, когда монады в JavaScript полезны.

Я прочитал кучу статей о Monads в JavaScript и понял, что jQuery - один из примеров его использования. Но кроме схемы "цепочки", какие другие проблемы могут быть эффективно решены с помощью монад в разработке переднего плана?

Ref:

http://importantshock.wordpress.com/2009/01/18/jquery-is-a-monad/

http://igstan.ro/posts/2011-05-02-understanding-monads-with-javascript.html

4 ответа

Решение

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

  1. JQuery оборачивает элементы DOM и дает более богатый интерфейс. Решаемых проблем множество: более богатые события ("mouseenter","mouseleave","hashchnged" и т. Д.). Привязка событий добавляет обработчики вместо переопределения. Интерфейс для обработки CSS похож на другие интерфейсы, предоставляемые JQuery.

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

Не говоря уже о том, что он сохраняет много ошибок при обращении к нулям. Если у меня нет элемента с идентификатором guy, затем работает $("#guy").text("I am not here") не вызовет ошибку в JQuery.

  1. JQuery легко оборачивается вокруг элемента DOM, позволяя перемещаться назад и вперед между необработанным интерфейсом JS и JQuery. Это позволяет разработчикам изучать JQuery в своем собственном темпе, а не переписывать весь код за один раз.

  2. Когда JQuery передает обратный вызов с аргументами, он использует объект DOM вместо оболочки JQuery. Это позволяет сторонним разработчикам легко интегрироваться с JQuery, поскольку им не нужно полагаться на JQuery. Например, допустим, я написал функцию, которая окрашивает текст в красный цвет, используя сырой JavaScript. function paintRed(element){element.style.color="red"} - Я могу легко передать эту функцию в качестве обратного вызова функции JQuery.

Вот моя попытка помочь новичкам, которых вы, вероятно, больше нигде не нашли.

Монада - это легко компонуемая единица (разновидность строительных блоков программирования) в функциональном программировании.

(IMO, введение "законов монады" без какого-либо контекста и рационализации - просто бесполезная классификация и опасность для понимания концепции. Не волнуйтесь, я делаю работу позже в этой статье.)

В большинстве случаев у нас есть много видов строительных блоков программирования, таких как объект, функция, список и т. Д.

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

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

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

На самом деле, эта мудрость распространена в мире ПК в наши дни.

USB, сокращение от Universal Serial Bus, является отраслевым стандартом, который был разработан для определения кабелей, разъемов и протоколов для соединения, связи и питания между персональными компьютерами и их периферийными устройствами.

Получение хорошо спроектированного универсально стандартизированного строительного блока устраняет многие проблемы.

  1. Объект (раньше) был один.
  2. Функция одна.
  3. Монада это одна.
  4. Характеристики
  5. Реализация
  6. верификация

1.OOP

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

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

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

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

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

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

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

Функциональное программирование - это все о создании функций.

Сказать это легко, но это довольно большое достижение в истории программирования.

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

Я был программистом на C#(ООП) начиная с версии 1.0, и в целом я был удовлетворен, но почувствовал что-то очень неправильное, но не знал, что это было.

Позже я стал программистом JavaScript, и в первые дни я писал так:

```JS

function add1(a) {
    return a + 1;
}

```

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

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

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

Конечно, в C#1.0 уже реализован делегат, и я немного понимаю, что это что-то во внутреннем механизме событий. В конце концов, C# был основным языком ООП и довольно уродлив для функционального программирования, по крайней мере, в версии 1.0.

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

Итак, теперь я пишу это:

```JS

const add1 = x => x + 1;
const add2 = x => x + 2;
[1, 2, 3].map(add1); //[2,3,4]
[1, 2, 3].map(add2); //[3,4,5]

```

или же

```JS

const plus = (x) => (y => x + y);
plus(1)(5); //6

```

На самом деле, это то, что мне очень нужно в программировании на C#, это было что-то очень неправильное, о чем я чувствовал.

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

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

Функция BEFORE => AFTER,

Основная идея состоит в том, чтобы составлять функции.

Когда вы сосредоточены на функциональной композиции, вы заботитесь только о различных композициях BEFORE => AFTER,

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

Блок-схема кодирования называется императивным программированием, и, вообще говоря, она глючная и слишком сложная. ООП стремится стать этим стилем.

С другой стороны, функциональное программирование автоматически приводит стиль программирования к https://en.wikipedia.org/wiki/Declarative_programming, и, вообще говоря, оно не глючит и не легко отлаживается.

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

3.Monad

Кстати, я не буду использовать здесь код на Hask ell.

Для большинства людей основным препятствием для понимания вещей монады является

  1. Для того, чтобы выучить монаду, начинающий должен быть знаком с кодом и терминами Hask ell.
  2. Чтобы освоить код и термины на Hask ell, новичку необходимо выучить монаду.

Это "Что было первым: курица или яйцо?" проблема. Обязательно избегайте.

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

Люди могут учиться только на основе того, что они уже знали.

Итак, вернемся к коду JavaScript.

Функции выглядят как составные единицы, но как насчет этого?

console.log("Hello world!");

Это один из самых простых JS-кодов, и, безусловно, это функция.

Нажмите клавишу F12 в ChromeBrowser и скопируйте и вставьте код в консоль разработчика.

Hello world!
undefined

Хорошо, код выполнил задачу, чтобы показать "Hello world!" на консоли, однако, возвращаемое значение console.log функция undefined,

Чтобы составить функции, ситуация неудобна; неудобная функция.

С другой стороны, есть удобная функция. Давайте исследуем следующий код:

```JS

const add1 = x => x + 1;
[1, 2, 3].map(add1); //[2,3,4]

```

Массив в JavaScript ведет себя довольно хорошо в мире функционального программирования.

[1, 2, 3].map(add1) //[2,3,4]

указывает:
ArrayFunction=>Array

Вход и выход функции одного типа: Array,

Математическая структура одинакова во всем BEFORE => AFTER,

Природа последовательности и идентичности прекрасна.

Интригующее сходство с интерфейсом USB, естественно, наводит на мысль:
ArrayFunction=>ArrayFunction=>ArrayFunction=>Array...

В коде JavaScript:

```JS

  [1, 2, 3]
    .map(add1) //[2,3,4]
    .map(add1) //[3,4,5]
    .map(add1);//[4,5,6]

```

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

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

Когда у нас есть:
Array.map(F).map(F).map(F)...

принимая во внимание .map(F) является специфичным для массива JavaScript синтаксисом, замена его на более лаконичный синтаксис возможна, например, с использованием некоторого транспилятора, такого как Babel.

Так что замена .map(F) в *F:
Array*F*F*F...

Это похоже на алгебру.

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

В алгебре

a
= 0+a
= 0+0+a
= 0+0+0+a

или же

a
= 1*a
= 1*1*a
= 1*1*1*a

0 в +(сложение) операции,

a + 0 = a  //right identity
0 + a = a  //left identi

1 в *(умножении) работе,

a ∗ 1 = a  //right identity
1 ∗ a = a  //left identity

называется элементом идентичности.

В алгебре

1 + 2 + 3 = 1 + 2 + 3
(1+2) + 3 = 1 + (2+3)
    3 + 3 = 1 + 5
        6 = 6

называется ассоциативным свойством

number + number = number

number * number = number

string + string = string

"Hello" + " " + "world" + "!" 
= "Hello world" + "!" 
= "Hello "+ "world!"

также является ассоциативным, и элемент "",

Итак, каков элемент идентификации в функциональном программировании?

Что-то вроде:

identityF * f = f = f * identityF

Каково это ассоциативное свойство в функциональном программировании?

const add1 = x => x + 1;
const add2 = x => x + 2;
const add3 = x => x + 2;

Что-то вроде:

add1 * add2 * add3
= (add1 * add2) * add3
= add1 * (add2 * add3)

или ```

 (add1)(add2)(add3) = (add1)(add2)(add3)
((add1)(add2))(add3) = (add1)((add2)(add3))
        (add3)(add3) = (add1)(add5)
              (add6) = (add6)

```

Функциональное программирование - это все о композиции функций.

Что нам нужно в функциональном программировании

function * function = function

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

Фактически, у нас может быть "Алгебраическая спецификация JavaScript"(Спецификация для взаимодействия общих алгебраических структур в JavaScript)

введите описание изображения здесь

Так является ли массив JavaScript так называемым Monad?

Нет, но близко. Массив JavaScript можно классифицировать как Functor.

Монада - это особая форма Functor, с некоторыми дополнительными природами (больше правил).

Функтор по-прежнему является одним из самых составных элементов.

Итак, мы приближаемся к Монаде. Пойдем дальше.

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

Так что насчет значений JavaScript, кроме массивов? как насчет функций?

Изучая и следуя алгебраической спецификации JavaScript, было бы легко попытаться реализовать различные составные модули, включая Functor или Monad, какой смысл?

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

4.Specification

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

Итак, вот проблема установления:
Реализуйте структуру Math, которая генерирует автономную область, и посмотрите, как она работает.

Все хорошо, и я начну с нуля, но у меня уже есть хорошая модель для сравнения.

JavaScript Array
Array.map(F).map(F).map(F)...

Вместо царства Массив, давайте сделаем мой оригинал M царство как это:
M.map(F).map(F).map(F)...

Я думаю Array.map не является кратким синтаксисом, M сам по себе является функцией:
M(F)(F)(F)...

Хорошо, это хорошая дисциплина, всегда использовать определенный предварительно выбранный блок, который универсально стандартизирован. Это идея начать, так что, вероятно, F также должно быть M:
M(M)(M)(M)...

Хм, что это значит??

Итак, вот моя безумная идея.

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

Это безумие, как сказать: "Любые значения - массив!".

Если быть точным, то это безумие, если оно в сфере JavaScript, но вполне законно, если оно в автономной области Array.

Итак, я спроектирую что оригинал M царство будет обрабатывать любое голое значение / объект / функцию как M

Например, в M царство, когда голое значение: 5 найден, интерпретируется как M(5),

Другими словами, пока в M царство, программист не должен писать M(5) поскольку 5 неявно интерпретируется как M(5),

Соответственно в M область:

5
= M(5)
= M(M(5))
= M(M(M(5)))
...

В результате я нашел M является несколько прозрачным и, M должен быть элементом идентичности в области.

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

Композиция функции является ассоциативной для функционального программирования.

M должен быть гибко написан для составления функций:

js const add1 = x => x + 1; M(10)(add1); //11 M(10)(add1)(add1); //12 M(10)(add1)(add1)(add1); //13 const add2 = M(add1)(add1); M(10)(add2); //12 const add3 = M(add2)(add1);
M(10)(add3); //13

Также состав функций высшего порядка:

js const plus = (x) => (y => x + y); M(plus(1)(5)); //6 M(5)(M(1)(plus)); //6 const plus1 = M(1)(plus); M(5)(plus1)(; //6

5.Implementation

Вот реализация M:

```JS

const compose = (f, g) => (x => g(f(x)));
const isMonad = (m) => !(typeof m.val === "undefined");

const M = (m = []) => {
  const f = m1 => {
    try { //check type error
      return M(M(m1).val(m));
    } catch (e) {
      return M(compose(m, M(m1).val)); // f-f compose
    };
  };
  f.val = m;
  return isMonad(m)
    ? m
    : f;
};
M.val = m => m;

```

Функция регистрации:
```JS

const log = (m) => (typeof m !== 'function')
  ? (() => {
    console.log(m);
    return m;
  })()
  : err();

```

Тестовый код:

```JS

const err = () => {
  throw new TypeError();
};

const log = (m) => (typeof m !== 'function')
  ? (() => {
    console.log(m);
    return m;
  })()
  : err();

const loglog = M(log)(log);
M("test")(loglog);

M("------")(log);
M([1])(log);
M(M(M(5)))(log)
M(99)(M)(log)

M("------")(log);
M([1, 2, 3])(([a, b, c]) => [a + 1, b + 1, c + 1])(log)

M("------")(log);

const add1 = a => (typeof a == 'number')
  ? a + 1
  : err();

M(10)(add1)(log); //11
M(10)(add1)(add1)(log); //12
M(10)(add1)(add1)(add1)(log); //13
const add2 = M(add1)(add1);
M(10)(add2)(log); //12
const add3 = M(add2)(add1);
M(10)(add3)(log); //13

M("------")(log);
const plus = (x) => (y => x + y);
M(plus(1)(5))(log); //6
M(5)(M(1)(plus))(log); //6
const plus1 = M(1)(plus);
M(5)(plus1)(log); //6

M("------")(log);
const map = (f) => (array => array.map(f));
const map1 = M(add1)(map);
M([1, 2, 3])(log)(map1)(log);

//===

M("left identity   M(a)(f) = f(a)")(log);
M(7)(add1)(log) //8

M("right identity  M = M(M)")(log);
console.log(M) //{ [Function: M] val: [Function] }
console.log(M(M)) //{ [Function: M] val: [Function] }

M("identity")(log);
M(9)(M(x => x))(log); //9
M(9)(x => x)(log); //9

M("homomorphism")(log);
M(100)(M(add1))(log); //101
M(add1(100))(log); //101

M("interchange")(log);
M(3)(add1)(log); //4
M(add1)(f => f(3))(log); //4

M("associativity")(log);
M(10)(add1)(add1)(log); //12
M(10)(M(add1)(add1))(log); //12

```

Вывод: ```консоль

test
test
------
[ 1 ]
5
99
------
[ 2, 3, 4 ]
------
11
12
13
12
13
------
6
6
6
------
[ 1, 2, 3 ]
[ 2, 3, 4 ]
left identity   M(a)(f) = f(a)
8
right identity  M = M(M)
{ [Function: M] val: [Function] }
{ [Function: M] val: [Function] }
identity
9
9
homomorphism
101
101
interchange
4
4
associativity
12
12

```

Ок, сработало.

M это очень сложная единица в функциональном программировании.

6.Verification

Итак, это так называемая монада?

Да.

https://github.com/fantasyland/fantasy-land

монада

Значение, которое реализует спецификацию Monad, должно также реализовывать спецификации Applicative и Chain. 1. M.of(a).chain(f) эквивалентно f(a) (левая личность) 2. m.chain(M.of) эквивалентно m (правильная личность)

левый тождество M(a)(f) = f(a)

js M(7)(add1) //8 M(add1(7)) //8

правильная идентичность M = M(M)

js console.log(M) //{ [Function: M] val: [Function] } console.log(M(M)) //{ [Function: M] val: [Function] }

Прикладное

Значение, которое реализует спецификацию Applicative, должно также реализовывать спецификацию Apply. 1. v.ap(A.of(x => x)) эквивалентно v (личность) 2. A.of(x).ap(A.of(f)) эквивалентно A.of(f(x)) (гомоморфизм) 3. A.of(y).ap(u) эквивалентно u.ap(A.of(f => f(y))) (Обмен)

идентичность

js M(9)(M(x => x)) //9

гомоморфизм

js M(100)(M(add1)) //101 M(add1(100)) //101

обмен

js M(3)(add1) //4 M(add1)(f => f(3)) //4

цепь

Значение, которое реализует спецификацию Chain, также должно реализовывать спецификацию Apply. 1. m.chain(f).chain(g) эквивалентно m.chain(x => f(x).chain(g)) (Ассоциативность)

ассоциативность

js M(10)(add1)(add1) //12 M(10)(M(add1)(add1)) //12

Вы можете избежать использования глобальных переменных и состояния при использовании монад (например, "чистый" код). Вы также можете взглянуть на https://github.com/brownplt/flapjax/. Flapjax - это библиотека функционально-реактивного программирования, которая также использует монадический подход.

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

/* Unit function */
function Monad(value)
  {
  // Construct monad and set value to given argument or undefined
  this.value = value || undefined;
  }

/* Constructor function */
Monad.prototype.pass = function(value, cb, scope)
  {
  // return constructor result if no default value is passed
  if (/undefined/.test(this.value) )
    {
    return new this.constructor();
    }
  // return callback result for given value in given context if scope is passed
  if(scope)
    {
    /* Bind function */
    return cb.call(scope, value);
    }
  // return callback result for given value otherwise
  return cb(value);
  }

 /* Separate arguments from function, and function from global scope */
 var foo = new Monad(RegExp);
 var bar = foo.pass(2, Function("count","return ++count"), Math);

Рекомендации

Другие вопросы по тегам