Recently I am learning JavaScript functional programming, and I am very interested in the famous curry. The curry function can accept a function, let’s call it the original function for the time being, and it returns a function, curried. Function, this returned curried function is very powerful. During the execution process, it continuously returns a function that stores the passed parameters until the conditions for the execution of the original function are triggered. This is more general, so let’s give an example to illustrate:
Original function:
var add = (x, y) => x + y
Curried function:
var curryAdd = curry(add)
This add requires two parameters, but Our curryAdd execution can pass in fewer parameters. When the parameters passed in are less than the parameters required by add, the add function will not be executed. curryAdd will write down the parameters and return another function. This function You can continue to execute the incoming parameters. We will have a variable to record the incoming parameters. If the total number of incoming parameters is equal to the total number of parameters required by add, we will activate the original parameter execution and return the results we want.
// 此时只传入了一个参数 根据判断返回的是一个函数 var add2 = curryAdd(2) // add2 = function(...) {}
// 此时累计传入了两个参数 等于了add需要参数的总和 所以返回的是一个结果 // 相当于执行了add(2)(3) var result = add2(3) // result = 5
It’s pretty good, right? Well, our goal is to write this magical curry function, and we have to write it in one line. Don’t worry, first analyze how to write it, and then go step by step. Optimization.
Based on the above description, let’s take a look at what the curry function needs. First, we need a variable to store the number of parameters of the original function. We know that function has an attribute called length, and that’s it. We Use limit to save it
var curry = function(fn) { var limit = fn.length ... }
The curry function should return a function. This function needs to be executed. Then the problem is that we need to judge whether the execution of this function activates the execution of the original function. The problem occurs when the incoming parameters above. Return function or result? This is indeed a problem. Let's write the return result first. When the parameters passed in are equal to the parameters required by the original function, we execute the original function fn
var curry = function(fn) { var limit = fn.length return function (...args) { if (args.length >= limit) { return fn.apply(null, args) } } }
. Otherwise, we have to return a function that stores the parameters. Function, there are two points here. One is that we need to record the history of the parameters passed in, and the other is what the returned function needs to do.
var curry = function(fn) { var limit = fn.length return function (...args) { if (args.length >= limit) { return fn.apply(null, args) } else { return function(...args2) { } } } }
See it, we only need to accumulate the parameters executed by the returned function. This achieves the purpose of recording the parameters passed in, so we thought of concat to args.concat(args2), and so on. What the function we return has to do is to repeat the above things, that is, the function with the parameter args needs to What it does, so it needs a name, otherwise we can't execute it, we call it judgeCurry
So as we said, either return a function or execute the original function.
var curry = function(fn) { var limit = fn.length return function judgeCurry (...args) { if (args.length >= limit) { return fn.apply(null, args) } else { return function(...args2) { return judgeCurry.apply(null, args.concat(args2)) } } } }
We finally finished writing this magical curry function. It is really powerful and combined with compose, it is really cool.
Our goal is to write the above function in one line, one line? how to write? By the way, I'm using ES6, so I've been going through a lot of trouble
var currySingle = fn => judgeCurry = (...args) => args.length >= fn.length ? fn.apply(null, args) : (...args2) => judgeCurry.apply(null, args.concat(args2))
Okay, let's see what's wrong. By the way, in order to not use the limit parameter, we have to assign a value when using it. The assignment can't be done in one line. It will become like this
var currySingle = fn => { var limit = fn.length var judgeCurry = null return judgeCurry = (...args) => args.length >= limit ? fn.apply(null, args) : (...args2) => judgeCurry.apply(null, args.concat(args2)) }
When we need to judge the parameters, we constantly evaluate fn.length, but the value of fn.length is certain. We don’t want to evaluate it every time, but we don’t want to use limit. Yes, what can be done? You must have thought of executing the function immediately! !
var currySingle = fn => ((limit) => judgeCurry = (...args) => args.length >= limit ? fn.apply(null, args) : (...args2) => judgeCurry.apply(null, args.concat(args2)))(fn.length)
I have to sigh at the magic of javascript. Finally, we wrote this magical curry in one line.
The above is the content of curry implementation in JavaScript functional programming. For more related content, please pay attention to the PHP Chinese website (www.php.cn)!