2016-07-28 8 views
0

Wenn f :: (a, b) -> C, können wir definieren Curry (f) wie folgt:Currying in JavaScript-Funktion mit n Parametern

Curry (f) :: ((a, b) -> c) -> a -> b -> c

const curry = f => a => b => f(a, b); 
const sum = curry((num1, num2) => num1 + num2); 
console.log(sum(2)(3)); //5 

Wie wir generische Curry-Funktion implementieren, die eine Funktion mit n Parametern übernimmt?

+0

Meinst du 'f :: ((a, b) -> c) -> (a-> b-> c)'? –

+0

@Patrick Roberts ja –

+1

Ich liebe diese Curry-Herausforderungen. Ich sollte eine Bibliothek oder etwas mit einer Reihe von Curry-Programmen schreiben, vielleicht finden es Leute, die es wert sind, benutzt zu werden. –

Antwort

3

Wenn ich richtig verstehe, ich glaube, dies ist der Weg ES6 zu gehen mit:

const curry = f => { 
 
    const nargs = f.length; 
 
    const vargs = []; 
 
    const curried = (...args) => vargs.push(...args) >= nargs ? f(...vargs.slice(0, nargs)) : curried; 
 
    
 
    return curried; 
 
}; 
 

 
const arg2 = curry((a, b) => a + b); 
 
const arg3 = curry((a, b, c) => a * (b + c)); 
 
const arg4 = curry((a, b, c, d) => Math.pow(a, b * (c + d))); 
 

 
console.log(arg2(1)(2)); // 1 + 2 
 
console.log(arg3(2)(3)(4)); // 2 * (3 + 4) 
 
console.log(arg4(2)(1, 3)(4)); // 2^(1 * (3 + 4))

Wenn Sie dies in ES5 tun möchte, ist hier eine etwas ausführlichere Methode :

function curry(f) { 
 
    var nargs = f.length; 
 
    var vargs = []; 
 
    
 
    return function curried() { 
 
    var args = Array.prototype.slice.call(arguments); 
 

 
    return vargs.push.apply(vargs, args) >= nargs ? f.apply(this, vargs.slice(0, nargs)) : curried; 
 
    }; 
 
} 
 

 
var arg2 = curry(function (a, b) { 
 
    return a + b; 
 
}); 
 
var arg3 = curry(function (a, b, c) { 
 
    return a * (b + c); 
 
}); 
 
var arg4 = curry(function (a, b, c, d) { 
 
    return Math.pow(a, b * (c + d)); 
 
}); 
 

 
console.log(arg2(1)(2)); // 1 + 2 
 
console.log(arg3(2)(3)(4)); // 2 * (3 + 4) 
 
console.log(arg4(2)(1, 3)(4)); // 2^(1 * (3 + 4))

+0

@Patrick Roberts Ihre Implementierung ist sehr kurz. –

+1

@PatrickRoberts: Gah, ich war [hier] (http://www.ecma-international.org/ecma-262/7.0/index.html#sec-functioninitialize), und falsch "aufzählbar" als "konfigurierbar" gelesen. Ausgezeichnet, das macht die Dinge viel einfacher. –

+1

@ T.J.Crowder schau dir mein Update an;) –

2

Vorbehalt: Ich habe keinen funktionalen Hintergrund, daher kann meine Terminologie ein bisschen abweichen.

Wenn von „Curry“ Sie bedeuten „erstellen Sie eine neue Funktion, die das Original mit einigen Argumenten vorgefüllte, wird im Folgenden“ die allgemeine Lösung in ES5 und früher ist wie folgt (siehe Kommentare):

// Add a function to the function prototype 
 
Object.defineProperty(Function.prototype, "curry", { 
 
    value: function() { 
 
    // Remember the original function 
 
    var f = this; 
 
    // Remember the curried arguments 
 
    var args = Array.prototype.slice.call(arguments); 
 
    // Return a new function that will do the work 
 
    return function() { 
 
     // The new function has been called: Call the original with 
 
     // the curried arguments followed by any arguments received in 
 
     // this call, passing along the current value of `this` 
 
     return f.apply(this, args.concat(Array.prototype.slice.call(arguments))); 
 
    }; 
 
    } 
 
}); 
 

 
// Usage: 
 
function foo(a, b, c) { 
 
    console.log(a, b, c); 
 
} 
 
var f = foo.curry(1, 2); 
 
f(3);

In ES2015 +, können wir Rest args statt arguments verwenden:

// REQUIRES ES2015+ support in your browser! 
 

 
// Add a function to the function prototype 
 
Object.defineProperty(Function.prototype, "curry", { 
 
    value: function(...curriedArgs) { 
 
    // Remember the original function 
 
    let f = this; 
 
    // Return a new function that will do the work 
 
    return function(...args) { 
 
     // The new function has been called: Call the original with 
 
     // the curried arguments followed by any arguments received in 
 
     // this call, passing along the current value of `this` 
 
     return f.apply(this, curriedArgs.concat(args)); 
 
    }; 
 
    } 
 
}); 
 

 
// Usage: 
 
function foo(a, b, c) { 
 
    console.log(a, b, c); 
 
} 
 
let f = foo.curry(1, 2); 
 
f(3);

+0

Entschuldigung, es fehlte ein ')', bemerkte erst, als ich die Snippets hinzufügte. –

+0

Ich denke, wir haben die Frage auf unterschiedliche Weise interpretiert, ich denke, wir werden sehen, wessen Interpretation richtig war: P –

+0

@PatrickRoberts: In der Tat! :-) Sie sind beide gute Antworten auf die Frage, die sie beantworten, wir werden sehen, welche Antworten die Frage des OP gibt. –

0

ES6/2015

const curry = fn => function curried(cargs) { 
 
    return cargs.length >= fn.length ? fn.apply(this, cargs) : (...args) => curried([...cargs, ...args]) 
 
}([]); 
 

 
const arg2 = curry((a, b) => a + b); 
 
const arg3 = curry((a, b, c) => a * (b + c)); 
 
const arg4 = curry((a, b, c, d) => Math.pow(a, b * (c + d))); 
 

 
console.log(arg2(1)(2)); // 1 + 2 
 
console.log(arg3(2)(3)(4)); // 2 * (3 + 4) 
 
console.log(arg4(2)(1, 3)(4)); // 2^(1 * (3 + 4))

ES5

var curry = function(fn) { 
 
    var args = Array.prototype.slice.call(arguments); 
 
    if (args.length - 1 >= fn.length) return fn.apply(this, args.slice(1)); 
 
    return function() { 
 
    return curry.apply(this, args.concat.apply(args, arguments)); 
 
    }; 
 
}; 
 

 
var arg2 = curry(function(a, b) { 
 
    return a + b; 
 
}); 
 
var arg3 = curry(function(a, b, c) { 
 
    return a * (b + c); 
 
}); 
 
var arg4 = curry(function(a, b, c, d) { 
 
    return Math.pow(a, b * (c + d)); 
 
}); 
 

 
console.log(arg2(1)(2)); // 1 + 2 
 
console.log(arg3(2)(3)(4)); // 2 * (3 + 4) 
 
console.log(arg4(2)(1, 3)(4)); // 2^(1 * (3 + 4))

0

Es gibt eine einfache Möglichkeit, Ihre sum Funktion Witz Curry h unbegrenzte Parameter.

const add = (a) => { 
 
    const next = b => add(a + b); 
 
    next.valueOf =() => a 
 
    return next; 
 
}; 
 

 
const one = add(1); 
 
console.log(one.valueOf()); 
 

 
const two = one + 1; 
 
console.log(two); 
 

 
const four = two + two; 
 
console.log(four) 
 

 
const six = add(four)(two); 
 
console.log(six.valueOf()); 
 

 
const eleven = six(4)(1); 
 
console.log(eleven.valueOf());

Diese add Funktion jedes Mal, wenn Sie mit einem anderen Parameter ausführen würde die curried Funktion aufrufen. Wie im Fall für const six = four + two; Es gibt den Wert von zwei vorherigen Aufrufen zurück und die Kette geht weiter und weiter.

Denken Sie daran, dass, um den primitiven Wert zu erhalten, müssen wir .valueOf() aufrufen.