Это монада? - PullRequest
       9

Это монада?

13 голосов
/ 20 февраля 2011

Я пытаюсь понять концепцию монад и хочу узнать, является ли этот код реализацией этой концепции (в JavaScript).

У меня есть функция M, которая возвращает новый объект, для которого установлен методкоторые создают метод-обертку

var foo = M().set('getX', function() { 
  return this.x; 
}).set('setX', function(x) { 
  this.x = x;
}).set('addX', function(x) { 
  this.x += x;
});

И тогда я могу связать метод foo

foo.setX(10).addX(20).addX(30).getX()

, вернёт 60

и то же самое, если у меня есть объект с методами и вызовомM с этим объектом.

var foo = {
  x: 10,
  add: function(x) {
    this.x += x;
  }
};

M(foo).add(10).add(20).add(30).x

вернет 70

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

f = M({x: 20}).set('getX', function() {
   return this.x; 
}).set('addX', function(x) {
   this.x += x;
}).addX(10).getX

поэтому f - это функция с контекстом объекта, заключенного в M - если я вызову f(), он вернет 30.

Правильно ли я понимаю?Является ли М монадой?

РЕДАКТИРОВАТЬ модифицированный код на github https://github.com/jcubic/monadic

Ответы [ 2 ]

14 голосов
/ 20 февраля 2011

Это моноидный паттерн. Каждая операция обновления состояния, такая как .setX(10), .addX(20) и т. Д., Является вычислением, которое преобразует один объект. (Чтобы быть синтаксически действительным, вы должны написать его как однопараметрическую функцию function(x) {x.addX(20);}, но я думаю, что будет понятнее, если я использую краткую форму.)

Две вещи делают это моноидом. Во-первых, есть элемент идентичности: .addX(0) ничего не делает с его объектом. Во-вторых, любые две операции могут быть объединены. Например, .setX(10).addX(20) также является вычислением, которое преобразует один объект.

Это не монада. Вычисления, поддерживаемые вашими методами, ограничены написанием и обновлением this.x. (.getX() не является членом моноида, потому что после него вы ничего не можете связать). Например, с монадой вы можете заставить одного члена цепочки операций выполнить if-then-else, чтобы решить, что будет дальше в цепочке. Ваши методы не могут этого сделать.

0 голосов
/ 24 августа 2015

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

Опять же, насколько я понимаю, моноид - это группа (в абстрактном алгебраическом смысле), замкнутая в операции single , отображающей один тип в себя.Если у вас было только реализовано add, то вы могли бы сказать , что ваша цепочка прототипов реализовала моноид.Но даже в этом случае вам придется вручную указывать сокращение в виде двоичной операции между каждым и каждым аргументом, например, так:

M({x:0}).add(1).add(2)...add(100) === 1050; // or _.reduce([1..100],add)

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

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

var bigOpFromLittleOps = 
       M({x:0})  .bind(function(x0){
return Madd(1)   .bind(function(x1){
return Madd(2)   .bind(function(x2){
...
return Madd(100) .bind(function(x100){
return Mreturn(x100);
}); ... });});})() === 1050; // Overkill

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

...