I’ve seen some currified articles lately, and I don’t know, it’s weird. One is a translation from Aliyun, which ends with this “Curry” :
function curry(fn, ... args) {
return (. _arg) = > {
returnfn(... args, ... _arg); }}Copy the code
Before the author clearly cited the difference between currization and partial application, the result finally said let’s implement currization, and then wrote a partial application…… So fake, I couldn’t help but comment:
Then today I saw the article of our group Huan Elder brother. To be honest, AFTER looking at the code at the beginning, I was not patient enough to see the specific analysis below:
// Define a placeholder
var _ = '_';
function magician3 (targetfn, ... preset) {
var numOfArgs = targetfn.length;
var nextPos = 0; // The index of the next valid input position, can be '_' or is the end of preset
// Check to see if there are enough valid arguments
if (preset.filter(arg= >arg ! == _).length === numOfArgs) {return targetfn.apply(null, preset);
} else {
// Returns the function 'helper'
return function (. added) {
// loop and add the added parameter to the preset parameter
while(added.length > 0) {
var a = added.shift();
// Obtains the position of the next placeholder, which can be '_' or the end of preset
while(preset[nextPos] ! == _ && nextPos < preset.length) { nextPos++ }/ / update the preset
preset[nextPos] = a;
nextPos++;
}
// Bind updated preset
return magician3.call(null, targetfn, ... preset); }}}Copy the code
What is this… Then huan elder brother they found this code has a bug, analyzed a, solved the bug, beautiful youth friends, go out to drink disco big health care is not good, must be so squandered life……
Before we implement it ourselves, for those of you who are not familiar with the concept of Currization, take a look at wiki. In a nutshell, Currization is the conversion of a multi-parameter function into a series of functions that accept a single parameter. It’s not quite the same concept as a partial application, which is “cutting” a multi-parameter function, whereas a coriation is “cutting” a function many times until every function in the middle is single-parameter, and the result is what’s called a Curried function. Writing a curried function in JS is really just writing a higher-order function, nothing special. So how do you implement a generic curry, and I’m not taking it personally, I mean both implementations are cute…
const curry = (fn) = > {
if (fn.length <= 1) return fn;
// This is my initial implementation
Fn. length (); // Fn. length ()
// const generator = (args) => (args.length === fn.length ? fn(... args) : arg => generator([...args, arg]));
const generator = (args, rest) = >(! rest ? fn(... args) :arg= > generator([...args, arg], rest - 1));
return generator([], fn.length);
};
Copy the code
All it takes is three lines of code (not counting function declarations).
const sum = (a, b, c) = > a + b + c;
const curriedSum = curry(sum);
const res = curriedSum(1) (2) (3)
console.log(res); / / 6
const log = (a, b, c) = > {
console.log(a, b, c);
};
const curriedLog = curry(log);
curriedLog('a') ('b') ('c'); // a b c
Copy the code
There seems to be no problem… Emmmmm… Slap in the face is welcome.
Therefore, before trying to curry partial application, I’d better think more about the basic concept of recursion, along with an FP-style quick sorting. Suddenly, I feel like WASTING my youth.
const quickSort = (list) = > {
if(! list || ! list.length)return [];
if (list.length === 1) return list;
const [middle, ...rest] = list;
const reducer = (acc, x) = > (
x <= middle ?
{ ...acc, left: [...acc.left, x] } : { ... acc,right: [...acc.right, x] }
);
const { left, right } = rest.reduce(reducer, { left: [].right: []});return [...quickSort(left), middle, ...quickSort(right)];
};
const list = [2.3.1.8.8.1.2.18.6.2333];
const sorted = quickSort(list); // [1, 1, 2, 2, 3, 6, 8, 8, 18, 2333]
Copy the code
PS: One of the big guys in the comment gave a one-line implementation:
const curry = (fn, arr = []) = >(... args) => (arg= >arg.length === fn.length ? fn(... arg) : curry(fn, arg) )([...arr, ...args])Copy the code
I can only use my brain to change my implementation into a line…
// The same idea as the three lines, but it is forced to write a line......
const curry = fn= >
(arg, args = [arg], rest = fn.length - 1) =>
(rest < 1? fn(... args) :newArg= > curry(fn)(newArg, [...args, newArg], rest - 1));
Copy the code
Comparing the two implementations above, we can see that my implementation… Failed, because since I have ARgs, this rest is redundant, so instead:
// It is better to split several lines...
const curry = fn= >(arg, args = [arg]) => (! fn.length || args.length === fn.length ? fn(... args) :newArg= > curry(fn)(newArg, [...args, newArg]));
Copy the code