javascript函数库_JavaScript函数库

javascript函数库

A curry is a spicy and tasty Indian dish usually made of vegetables in a thick sauce incorporating such spices as ginger, caraway, cayenne, and turmeric, often served over rice. But that’s not the type of curry I’m referring to today. I’m talking about the partial application of functions in JavaScript!

咖喱是一种辛辣可口的印度菜,通常由蔬菜制成,并用浓酱调味,加入姜,香菜,卡宴和姜黄等香料,通常在米饭上食用。 但这不是我今天要指的咖喱。 我说的是JavaScript中函数的部分应用!

Partial application, or currying, of a function is actually super easy to understand. Let’s start with a really simple example:

实际上,对函数的部分应用或使用Curry非常容易理解。 让我们从一个非常简单的示例开始:

const add = (x, y) ⟹ x + y

This is an uncurried binary function. It takes two parameters, both of which must be supplied at the same time:

这是一个未经处理的二进制函数。 它带有两个参数,必须同时提供两个参数:

const three = add(1, 2) //⟹ 3

Let’s give add a type signature, Haskell-style:

让我们add一个Haskell样式的类型签名:

//add :: (number ⟶ number) ⟶ numberconst add = (x, y) ⟹ x + y

The first part of the function is binary. It takes two parameters. It’s grouped with parenthesis so we know to expect to provide both parameters at the same time. Now let’s make a curried version:

函数的第一部分是二进制 。 它有两个参数。 它与括号组合在一起,因此我们知道期望同时提供两个参数。 现在让我们制作一个咖喱版:

//curried_add :: number ⟶ number ⟶ number
const curried_add
= x ⟹ y ⟹ x + y

In this version of add, we first take the x parameter, then we return a new function that takes the y parameter. We don’t get a result until we call both functions with parameters. This is made obvious in our type signature, in which we separate each step of the function with no parenthesis.

在此版本的add ,我们首先采用x参数,然后返回一个采用y参数的新函数。 在调用带有参数的两个函数之前,我们不会得到结果。 这在我们的类型签名中很明显,在该类型签名中,函数的每个步骤都没有括号地分开。

const three = curried_add(1)(2) //⟹ 3

But wait…that’s kind of silly. Well that’s because I’m leaving out what makes a curried function really useful. Let’s show how we can create a partially applied function with our curried add. We’ll forgo the curried_ prefix from now on, and assume add is curried.

但是等等……那真是愚蠢。 嗯,这是因为我遗漏了使咖喱函数真正有用的原因 。 让我们展示如何使用咖喱添加来创建部分应用的函数。 从现在开始,我们将不再使用curried_前缀,并假设add为curried。

const add2 = add(2) //⟹ y ⟹ 2 + y

We’ve partially applied our add function. That means we’ve supplied fewer than the total number of parameters, leaving us with a function that takes the remaining parameters. We can use this type of partial application to pre-load our functions. It makes a curried function highly reusable and easily specialized for custom functionality.

我们已经部分应用add函数。 这意味着我们提供的参数少于总数,剩下的函数需要我们处理。 我们可以使用这种类型的部分应用程序来预加载我们的功能。 它使咖喱函数具有高度可重用性,并且易于专门用于自定义功能。

The next benefit of currying your functions occurs when we are calling a function that expects a function as a parameter. Let’s imagine Array.prototype.map is our function in question. map is a function that takes a function which we use to transform each element of an array. We expect that function to take one parameter (most of the time anyway — you can incorporate index and array as well). Let’s see what happens if we try to use a function like add in that case:

调用函数的下一个好处是,当我们调用将函数作为参数的函数时。 假设Array.prototype.map是我们正在讨论的函数。 map是一个函数,它使用一个函数来转换数组的每个元素。 我们希望该函数采用一个参数(无论如何,大部分时间都可以—您也可以合并索引和数组)。 让我们看看如果在这种情况下尝试使用类似add的函数会发生什么:

const arr = [1, 2, 3]
arr.map(add) //⟹ [y ⟹ 1 + y, y ⟹ 2 + y, y ⟹ 3 + y]

Hmm, that’s kind of weird. Let’s try partially applying add first:

嗯,这很奇怪。 让我们先尝试部分应用添加:

const add5 = add(5)
arr.map(add5) //⟹ [6, 7, 8]

Ah, there we go, we had a function that expected one more parameter, we provided that parameter via map, and voila — our resultant array had expected number values inside! Notice how we only had to call it by name. We could’ve done this:

啊,走了,我们有一个函数,它希望再有一个参数,我们通过mapvoila提供了该参数我们的结果数组内部有期望的数值! 请注意,我们仅需按名称进行调用。 我们可以做到这一点:

arr.map(x => add5(x)) //⟹ [6, 7, 8]

But that’s ugly and requires constructing an anonymous function on the spot. We’d rather define our functions and call them by name, which is exactly what we did in the example prior to the previous one.

但这很丑陋,需要当场构造一个匿名函数。 我们宁愿定义我们的函数并通过名称来调用它们,这正是我们在上一个示例之前的示例中所做的。

There’s another thing that I’d like to share with you, and that’s an auto-curry function that we can wrap any function we like with to automatically allow us to provide any number of parameters, while returning either a) a function that takes the remainder, or b) the result of the call depending on whether we’ve supplied all the parameters or not:

我想与您分享另一件事,这是一个自动curry函数,我们可以包装我们喜欢的任何函数,以自动允许我们提供任意数量的参数,同时返回a)一个使用b)调用的结果,取决于我们是否提供了所有参数:

function curry(fn) {
const arity = fn.length
return function _curry(...args) {
return args.length < arity
? _curry.bind(null, ...args)
: fn.call(null, ...args)
}
}

We find the arity of the function by asking for its length property. Then we return a function that takes any number of parameters (...args) and recursively calls that function until all of the arguments that were necessary to call the original function have been supplied. We can use it like this:

我们通过询问其length属性来发现该函数的稀疏性。 然后,我们返回一个带有任意数量参数( ...args )的函数,并递归调用该函数,直到提供了调用原始函数所需的所有参数为止。 我们可以这样使用它:

const add = curry((x, y) ⟹ x + y)const add1 = add(1)const three = add(1, 2)

As you can see, you can now provide any number of arguments at a time within the same set of parenthesis, which can look a lot nicer when you want to provide more than one pre-loaded argument at a time. Plus, we can use this function on functions that aren’t naturally curried, allowing us to turn an uncurried function into a curried one. Sweet!

如您所见,现在您可以在同一组括号内一次提供任意数量的参数,当您想一次提供多个预加载的参数时,这看起来会更好。 此外,我们可以在非自然管理的函数上使用此函数,从而使我们可以将未管理的函数转换为已管理的函数。 甜!

But what if you’re trying to curry an existing function, but your parameters are out of order for you to do it conveniently?

但是,如果您要尝试使用现有功能,但参数却乱码怎么办呢?

const split = (str, delimiter) ⟹ str.split(delimiter)const slice = (str, start, end) ⟹ str.slice(start, end)const hasColon = str ⟹ str.includes(':')const ifEl = (predicate, truefn, falsefn) ⟹ data ⟹
predicate(data) ? truefn(data) : falsefn(data)const splitIfColon = ifEl(hasColon, split(??), slice(??,??))

Uh oh, even if I curry these functions, I need str to be in the tail parameter position — the last one I supply. But wait! Currying can still save us with a helper. Introducing flip:

嗯,即使我使用了这些函数,我也需要将str设置在tail参数位置,即我提供的最后一个参数位置。 可是等等! 咖喱仍然可以帮助我们。 flip介绍:

const flip2 = curry((f, b, a) ⟹ f(a, b))const flip3 = curry((f, b, c, a) ⟹ f(a, b, c))

flip and friends take the parameters out of order. We defer the function call via currying, not actually calling the provided parameters until we have them all. This nifty trick allows us to fix our code from earlier:

flip ,朋友将参数混乱。 我们通过currying推迟函数调用,直到我们全部拥有它们之后才实际调用提供的参数。 这个巧妙的技巧使我们可以从更早的时候修复代码:

const split = (str, delimiter) ⟹ str.split(delimiter)const slice = (str, start, end) ⟹ str.slice(start, end)const hasColon = str ⟹ str.includes(':')const ifEl = (predicate, truefn, falsefn) ⟹ data ⟹
predicate(data) ? truefn(data) : falsefn(data)const splitIfColon =
ifEl(hasColon, flip2(split(':')), flip3(slice(0, 2)))splitIfColon('who:what:where') //⟹ ["who", "what", "where"]
splitIfColon('why') //⟹ "wh"

Now, via some functional black magic, we can manipulate functions’ parameters to suit our needs and play nice with other functions!

现在,通过一些实用的黑魔法,我们可以操纵函数的参数以满足自己的需求,并与其他函数配合使用!

So now we’ve seen at least three good uses for currying — we can curry a function to pre-load it with parameters and define specialized custom functions from reusable ones, as demonstrated with add. We can supply parameters to return a function with the arity expected of a function parameter of another function, like we did with Array.prototype.map. Or we can change the order of existing functions’ parameters to suit our own function signatures’ needs.

因此,现在我们至少看到了三种用于curring的好用法-我们可以咖喱一个函数,以使用参数预加载该函数,并从可重用的函数中定义专用的自定义函数,如add 。 我们可以提供参数,返回一个函数预计另一个函数的函数参数的元数 ,像我们与做Array.prototype.map 。 或者,我们可以更改现有功能参数的顺序以适合我们自己的功能签名的需求。

Partial application is one of the major tenets of functional programming. It can provide the developer with extreme freedom as to how parameters are supplied to any given function. I hope this article helps clarify how to partially apply functions and how useful partial application can be!

部分应用是函数式编程的主要宗旨之一。 它可以为开发人员提供关于如何将参数提供给任何给定功能的极大自由度。 我希望本文有助于阐明如何部分应用函数以及部分应用可以有多大用处!

翻译自: https://medium.com/swlh/javascript-function-currying-768a0f1f3000

javascript函数库

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值