发布于 2026-01-06 1 阅读
0

🍛 Currying到底是什么?(含JavaScript)

🍛 Currying到底是什么?(含JavaScript)

我知道你们都垂涎三尺了,或许是JAMStack让开发世界变得太过诱人,而我现在又在谈论咖喱?所以,在你们被这些开发世界的奇迹“饿死”之前,让我先来介绍一下咖喱到底是什么。

柯里化(Currying)得名于Haskell Curry,柯里化的本质含义是将一个接受多个参数的函数转换为一个只接受一个参数并返回一个接受下一个参数的函数。

柯里化并非 JavaScript 特有的概念,它也是数学中的概念,就像function(还记得经典的 f(x) 吗?)

// Not curried
const add = (x, y) => x + y

// Curried
const add = x => y => x + y
const addFive = add(5)
addFive(6) // 11

正如你所看到的,使用柯里化,我们可以拥有功能更明确的函数,这反过来大大简化了我们的代码。

借助柯里化,我们可以预先加载带有参数的函数,以便接收一个能够记住这些参数的新函数。

让我们创建一个可以帮助我们对其他函数进行柯里化的函数。
现在请注意,
这个函数将接受一个函数作为参数fn,并返回一个$curry接受单个参数并执行该函数所执行的操作的函数fn

让我们一步一步来。

// This function takes a function `fn` as a parameter.
function curry(fn) {
  // Let us determine the arity of `fn`
  // Arity is the number of parameter taken by `fn`
  const arity = fn.length

  // ...
}
function curry(fn) {
  const arity = fn.length

  // Let's return the $curry function.
  // Let's have all the arguments ( ...args ) being passed in $curry
  // Remember we are returning a function so we can pass args in it.
  return function $curry(...args) {
    // ...
  }
}
function curry(fn) {
  const arity = fn.length
  return function $curry(...args) {
    // Let's return the function with all the passed arguments.
    // This code maybe stupid until you read the next para...
    return $curry.bind(null, ...args)

    // ...
  }
}

我们不能一直返回函数,我们需要一个结果。比如,把数字相加并得到输出结果。

我们来添加一个条件。

function curry(fn) {
  const arity = fn.length
  return function $curry(...args) {
    if (args.length < arity) {
      return $curry.bind(null, ...args)
    }
    return fn.call(null, ...args)
  }
}

通过比较参数的长度,args.length我们可以知道函数中传递了多少个参数。

当我演示如何使用该curry函数来柯里化其他需要多个参数的函数时,事情就会变得更加清晰。

为了简单起见,我们取一个add接受 3 个值(参数)的函数,并将它们相加。

const add = (x, y, z) => x + y + z

const curriedAdd = curry(add)

const addFive = curriedAdd(5) // args.length = 1

const addFiveAndSix = addFive(6) // args.length = 2

const output = addFiveAndSix(8) // args.length = 3

// The funciton can be called now as `args.length` < arity is false.
console.log(output) // 19

args.length之所以能够给出参数的数量,是因为return $curry.bind(null, ...args)……该$curry函数包含了传递给任何给定实例的所有参数。

希望这能解释清楚这个功能的工作原理。如果你还有其他疑问,可以在推特上告诉我。

@yashguptaz

为你的代码增添趣味。

柯里化允许一种称为部分应用的奇妙现象。
根据维基百科,部分应用可以定义为——

部分应用是指将一个函数的参数数量固定,从而生成另一个参数数量较少的函数的过程。

定义很简单,柯里化可以减少函数的参数数量。

让我们来看curry一个众所周知的功能map,看看它如何改变我们的生活。

// Before Currying
const allTheChildren = elements => map(elements, getChildren)

// Let's curry map
const map = curry((fn, f) => f.map(fn))

// AFter Currying
const allTheChildren = map(getChildren)

多次使用时,效果会非常明显map。这就是我们减少大量样板代码的方法。

几乎所有接受多个参数的函数都可以进行柯里化,并且可以使用部分应用。

是不是很棒?虽然我是个咖喱菜新手,但我发现分享起来很令人兴奋。如果你想分享一些东西、提出问题,或者想一起解决或理解一些问题,可以在推特上联系我。我的推特账号是@yashguptaz

请在推特上关注我,我会分享我使用函数式编程的经验。

文章来源:https://dev.to/yashguptaz/what-the-heck-is-currying-ft-javascript-jlp