2016-12-12 4 views
0

Кажется, что функции curry и partial выполняют то же самое. (Может быть, единственное различие в количестве аргументов)В чем разница между карри и частичной функцией в Рамде?

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

+0

Это почти такой же вопрос, как [В чем разница между каррированием и частичным приложением] (http://stackoverflow.com/q/218025/2907849) только без ссылки на рамда. – lonelyelk

+0

@lonelyelk: ... но поскольку «карри» Рамды несколько нестандартные, для этого может потребоваться собственный ответ. Я попробую свои собственные ниже. –

ответ

-2

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

Частичное применение функций - это тип каррирования. Фактически, если вы посмотрите на Ramda source code, вы увидите, что функция partial была реализована с использованием функции curry.

var _arity = require('./_arity'); 
var _curry2 = require('./_curry2'); 


module.exports = function _createPartialApplicator(concat) { 
    return _curry2(function(fn, args) { 
    return _arity(Math.max(0, fn.length - args.length), function() { 
     return fn.apply(this, concat(args, arguments)); 
    }); 
    }); 
}; 

Кроме того, обратите внимание на this question, которые объясняют различные принципиально.

+1

Это неверно: «Частичное применение функций - это тип каррирования». Currying является * преобразованием функции * типа типа (a, b, c) -> d' в функцию типа 'a -> b -> c -> d'. – davidchambers

4

Множество ответов от более широкого сообщества FP могут направить вас немного неправильно. Кармины Рамды, как мне кажется, несут дух currying из языков стиля ML в Javascript, но не являются строго одинаковыми.

Частичное применение, вероятно, довольно стандартное в Рамде. (Отказ от ответственности: я один из авторов Рамды.) Это также намного проще описать. partial функции Ramda в принимает функцию n аргументов и список k аргументов (для некоторых 0 < k < n), и возвращает новую функцию n - k аргументов, которые будут вызывать оригинальную функцию с новыми аргументами и оригинальными:

const f = (a, b, c, d, e) => a + b + c + d + e; 
// f :: a -> b -> c -> d -> e -> a + b + c + d + e 

const g = partial(f, [1, 2]); 
g.length; //=> 3 
g(3, 4, 5); //=> 15 
g(3); //=> NaN ≍ 1 + 2 + 3 + undefined + undefined) 
// g :: (c, d, e) -> 1 + 2 + c + d + e 

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

Каррирование - это немного другая история. В many languages функция curry преобразует функцию параметров n во вложенную последовательность 1-параметрической функции, так что (a, b, c) => f(a, b, c) преобразуется в a => (b => (c => f(a, b, c)), который может быть записан без путаницы как a => b => c => f(a, b, c). В Ramda мы немного более гибкие, позволяя вам поставлять столько аргументов, сколько вы выберете при одном вызове, каждый раз возвращаете функцию, пока не получите достаточные полные параметры для удовлетворения исходной функции, после чего мы вызываем это и вернуть это значение. Это, вероятно, проще объяснить на примерах:

const f = (a, b, c, d, e) => a + b + c + d + e; 
// f :: a -> b -> c -> d -> e -> a + b + c + d + e 

const h5 = curry(f); 
h5.length; //=> 5 

const h3 = h5(1, 2); 
h3.length; //=> 3 
h3(3, 4, 5); //=> 15 

const h2a = h3(3); 
h2a.length; //=> 2 
h2a(4, 5); //=> 15 

const h2b = h5(1, 2, 3); 
h2b.length; //=> 2 
h2b(4, 5); //=> 15 

const h2c = h5(1)(2, 3); 
h2c.length; //=> 2 
h2c(4, 5); //=> 15 

const h2d = h5(1)(2)(3); 
h2d.length; //=> 2 
h2d(4, 5); //=> 15 

const h1a = h3(3, 4); 
h1a.length; //=> 1 
h1a(5); //=> 15 

const h1b = h2a(4); 
h1b.length; //=> 1 
h1b(5); //=> 15 

// h5 :: (a, b, c, d, e) -> a + b + c + d + e 
// :: (a, b, c, d) -> e -> a + b + c + d + e 
// :: (a, b, c) -> (d, e) -> a + b + c + d + e 
// :: (a, b, c) -> d -> e -> a + b + c + d + e 
// :: (a, b) -> (c, d, e) -> a + b + c + d + e 
// :: (a, b) -> (c, d) -> e -> a + b + c + d + e 
// :: (a, b) -> c -> (d, e) -> a + b + c + d + e 
// :: (a, b) -> c -> d -> e -> a + b + c + d + e 
// :: a -> (b, c, d, e) -> a + b + c + d + e 
// :: a -> (b, c, d) -> e -> a + b + c + d + e 
// :: a -> (b, c) -> (d, e) -> a + b + c + d + e 
// :: a -> (b, c) -> d -> e -> a + b + c + d + e 
// :: a -> b -> (c, d, e) -> a + b + c + d + e 
// :: a -> b -> (c, d) -> e -> a + b + c + d + e 
// :: a -> b -> c -> (d, e) -> a + b + c + d + e 
// :: a -> b -> c -> d -> e -> a + b + c + d + e 

Поскольку curry настолько гораздо более гибким, я редко использую partial себя. Но есть люди, которые, гм, частично.