Есть ли способ предоставить окончательный метод преобразования при объединении операций (например, уменьшение карты) в underscore.js? - PullRequest
3 голосов
/ 28 марта 2012

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

Скажем, я хотел сделать такую ​​операцию:

  • взять массив [1,2,3]
  • умножить каждый элемент на 2 (карта): [2,4,6]
  • сложить элементы вместе (уменьшить): 12
  • умножить результатк 10: 120

Я могу сделать это довольно четко в подчеркивании, используя цепочку, например так:

arr = [1,2,3]
map = (el) -> 2*el
reduce = (s,n) -> s+n
out = (r) -> 10*r

reduced = _.chain(arr).map(map).reduce(reduce).value()
result = out(reduced)

Однако, было бы еще лучше, если бы я мог связать ''Метод тоже, как это:

result = _.chain(arr).map(map).reduce(reduce).out(out).value()

Теперь это было бы довольно простым дополнением к библиотеке, как подчеркивание.Но мои вопросы:

  • Есть ли у этого метода 'out' имя в функциональном программировании?
  • Существует ли это уже в подчеркивании (tap близко, но не совсем).

Ответы [ 2 ]

3 голосов
/ 29 марта 2012

Этот вопрос меня очень зацепил. Вот некоторые из моих мыслей.

Такое чувство, что использование underscore.js в режиме 'chain ()' выходит за рамки парадигмы функционального программирования. По сути, вместо вызова функций для функций вы вызываете методы экземпляра объекта-оболочки способом ООП.

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

arr = [1,2,3]
double = (arr) -> _.map(arr, (el) -> 2 * el)
sum = (arr) -> _.reduce(arr, (s, n) -> s + n)
out = (r) -> 10 * r

result = out sum double arr
# probably a less ambiguous way to do it would be
result = out(sum(double arr)) 

Глядя на настоящие функциональные языки программирования (как в ... гораздо более функциональных, чем JavaScript), кажется, что вы могли бы сделать то же самое там еще более простым способом. Вот та же самая программа, написанная на Standard ML. Обратите внимание, что вызов map только с одним аргументом возвращает другую функцию. Нет необходимости заключать эту карту в другую функцию, как в JavaScript.

val arr = [1,2,3];
val double = map (fn x => 2*x);
val sum = foldl (fn (a,b) => a+b) 0;
val out = fn r => 10*r;

val result = out(sum(double arr))

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

infix 1 |>;
fun x |> f = f x;

val result = arr |> double |> sum |> out

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

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

UPDATE

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

// extend underscore with partialr function
_.mixin({
  partialr: function (fn, context) {
    var args = Array.prototype.slice.call(arguments, 2);
    return function () {
      return fn.apply(context, Array.prototype.slice.call(arguments).concat(args));
    };
  }
});

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

var sum = _.partialr(_.reduce, this, function (s, n) { return s + n; });
sum([1,2,3]);

Я все же предпочитаю arr |> double |> sum |> out вместо out (sum (double (arr)))). Цепочка Underscore () хороша тем, что читает в более естественном порядке.

2 голосов
/ 23 апреля 2012

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

_.mixin({
  app: function(v, f) { return f (v); }
});

тогда вы можете делать то, что просили:

var arr = [1,2,3];
function m(el) { return 2*el; };
function r(s,n) { return s+n; };
function out(r) { return 10*r; };

console.log("result: " + _.chain(arr).map(m).reduce(r).app(out).value()));

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

...