草庐IT

柯里化

lio_zero 2023-03-28 原文

柯里化(Currying)是 lambda 演算中的一个概念。

柯里化是一个函数,它一次接受一个参数,并返回一个新函数,该函数期待下一个参数。它是一种函数转换,将 f(a,b,c) 转换为可以被以 f(a)(b)(c) 的形式进行调用。

JavaScript 中的柯里化是什么?

柯里化简单地说就是计算具有多个参数的函数,并将它们分解为具有单个参数的函数序列。

换句话说,柯里化是一个函数,而不是一次获取所有参数,获取第一个参数并返回一个新函数,该函数获取第二个参数并返回一个新函数,该函数获取第三个参数,以此类推,直到所有参数都完成。

为什么要用柯里化?

柯里化之所以理想,有几个原因:

  • 柯里化是一种检查方法,确保你在继续之前得到了所需的一切
  • 它可以帮助您避免一次又一次地传递同一个变量(参数复用)
  • 它将您的函数划分为多个较小的功能,可以处理一项职责。这使你的函数更纯粹,更不容易出错和产生副作用
  • 在函数式编程中,它用于创建高阶函数
  • 这可能是个人喜好,增强代码可读性

实现柯里化

柯里化是一个接受多个参数的函数。它将把这个函数转换成一系列函数,每个小函数都接受一个参数。

一个简单累加数示例:

// 非柯里化
const add = (a, b, c) => {
  return a + b + c
}
console.log(add(2, 3, 5)) // 10

// 柯里化
const addCurry = (a) => {
  return (b) => {
    return (c) => {
      return a + b + c
    }
  }
}

console.log(addCurry(2)(3)(5)) // 10

以上实现柯里化更简便的方法是,使用 ES6 的箭头函数,它可以帮助我们编写更少的代码:

const addCurry = (a) => (b) => (c) => a + b + c

console.log(addCurry(2)(3)(5)) // 10

高级柯里化

const curry = (fn) => {
  return (curried = (...args) => {
    if (fn.length !== args.length) {
      return curried.bind(null, ...args)
    }
    return fn(...args)
  })
}

const totalNum = (x, y, z) => x + y + z
const curriedTotal = curry(totalNum)

console.log(curriedTotal(10)(20)(30)) // 60

在上面的例子中,我们创建了一个需要固定数量参数的函数。

它接收一个函数 curry 作为外部函数。这个函数是一个包装函数。它返回另一个名为 curried 的函数,该函数接收带有扩展运算符 (…args) 的参数,并比较函数长度 fn.length

函数长度意味着无论我们在这里传递多少个参数,它都会反映在函数的长度属性中。

但是每次参数都会增加。如果我们需要的参数数量不相等,它将返回 curried。如果我们调用 bind,就会创建一个新函数并传递 (…args)

注意:bind 创建了一个新函数。

示例:操作 DOM

以下是一个简单的使用柯里化函数操作 DOM 示例:

const updateElemText = (id) => (content) =>
  (document.querySelector(`#${id}`).textContent = content)

const updateHeaderText = updateElemText('header')
updateHeaderText('Hello D.O!')

柯里化与偏函数

既然你知道了柯里化的工作原理,那么柯里化和偏函数(partial application)之间有什么区别?

  • 柯里化:一个接受多个参数的函数。它将把这个函数转换成一系列函数,其中每个小函数将接受一个参数,直到所有参数都完成。
  • 偏函数:当给定的参数少于预期的参数时,函数将转化为偏函数,并返回一个期望剩余参数的新函数。

示例:

const addPartial = (x, y, z) => {
  return x + y + z
}

const partialFunc = addPartial.bind(this, 2, 3)
partialFunc(5) // 10

当函数传递的某些参数不完整时,它被称为偏函数。

柯里化和偏函数并没有真正的区别;它们是相关的,但它们有不同的理论和应用。

更多资料

有关柯里化的更多相关文章

  1. ruby - 在 Ruby 中使用关键字参数柯里化(Currying) proc - 2

    假设我有一个通用的Proc、Lambda或method,它带有一个可选的第二个参数:pow=->(base,exp:2){base**exp}现在我想柯里化(Currying)这个函数,给它一个3的exp。cube=pow.curry.call(exp:3)这里有一个歧义,由关键字参数和新的散列语法引起,Ruby将exp:3解释为作为第一个参数传递的散列,base.这导致函数立即被调用,当#**被发送到散列时呈现NoMethodError。为第一个参数设置默认值同样会导致函数在柯里化(Currying)时立即被调用,如果我将第一个参数标记为必需,而不提供默认值:pow=->(base:

  2. ruby - Ruby 中的简单柯里化(Currying) - 2

    我正在尝试用ruby​​进行一些柯里化(Currying):defadd(a,b)returna+bendplus=lambda{add}curry_plus=plus.curryplus_two=curry_plus[2]#Line24putsplus_two[3]我得到了错误func_test.rb:24:in`[]':wrongnumberofarguments(1for0)(ArgumentError)来自func_test.rb:24:in`'但如果我这样做plus=lambda{|a,b|a+b}这似乎有效。但是通过在用lambda赋值之后打印加号,两种方式都返回相同类型的

  3. javascript - 如何使用 UnderscoreJS 进行柯里化(Currying)? - 2

    我正在尝试使用_.bind(...)。我知道如何使用绑定(bind)强制函数上下文,但还不知道如何进行柯里化(Currying)。我尝试的是:add=function(number){this.sum=this.sum+number;}add5=_.bind(add,{sum:0},5)但是,调用add5(),或者add5(5)似乎没有什么效果。任何线索如何包装参数,以便从一个调用到另一个调用保留上下文? 最佳答案 可能您想做部分应用,而不是currying/schönfinkeling。下划线有_.partial为此功能:func

  4. javascript - 取消 javascript 中 n 个参数的柯里化(Currying)函数 - 2

    如果f::a->b->c是柯里化(Currying)的,那么uncurry(f)可以定义为:uncurry::(a->b->c)->((a,b)->c)我正在尝试在javascript中实现上述功能。我的以下实现是否正确且足够通用,或者是否有更好的解决方案?constuncurry=f=>{if(typeoff!="function"||f.length==0)returnf;returnfunction(){for(leti=0;ia=>b=>f(a,b);constcurriedSum=curry((num1,num2)=>num1+num2);console.log(currie

  5. javascript - 在 React 中柯里化(Currying)事件处理程序 - 2

    我正在尝试在组件上编写一个(curried?)onChange事件处理程序,该组件将接收一个key参数,该参数将让它知道状态对象中的哪个键更新。代码无法编译,提示'key'isnotdefined。classAppextendsComponent{constructor(props){super(props);this.state={firstName:null,lastName:null}this.handleChange=this.handleChange.bind(this);}handleChange=(key)=(event)=>{console.log(key,event)

  6. javascript - 动态柯里化(Currying),以及如何在 JavaScript 变量中同时保存函数和值 - 2

    这个问题在这里已经有了答案:Variadiccurriedsumfunction(19个回答)关闭6年前。我正在学习JavaScript,我最近遇到了一个practiceproblem这要求我构建一个可以创建如下输出的函数:varthreeSum=sum(3);threeSum//3threeSum(4)//7threeSum(4)(3)//10threeSum(4)(3)(7)//17threeSum(4)(3)(7)()(2)//19threeSum-2//1threeSum+2//5我假设涉及柯里化(Currying),并且我认为我基本了解柯里化(Currying)如何以简单的形

  7. javascript - 如何在未知数量的参数上柯里化(Currying)一个函数 - 2

    假设我有一个名为multiplyDivide的函数如果我调用multiplyDivide(2)(3)(4)(6)它相当于2*3/4*6.更新:如果我事先不知道我将采用多少参数,是否可以编写这样的函数?例如,我可以有multiplyDivide(1)(2)或multiplyDivide(1)(2)(3)(4)...(n-1)(n) 最佳答案 这是可能的,但您需要定义终止条件,因为该问题本质上与编写递归函数的问题相同。该函数需要一种方法来判断它应该返回一个函数还是一个值。您如何表示对值(value)的需求取决于您。一种方法是检查是否传递

  8. javascript - 你如何柯里化(Currying)任意数量的任何 javascript 函数? - 2

    假设我有一些功能:functiong(a,b,c){returna+b+c}我想把它变成它的“curry”形式(在引号中,因为它本身并不完全是curry):functionh(a,b,c){switch(true){case(a!==undefined&&b!==undefined&&c!==undefined):returna+b+ccase(a!==undefined&&b!==undefined&&c===undefined):returnfunction(c){returna+b+c}case(a!==undefined&&b==undefined&&c===undefined

  9. javascript 柯里化(Currying) - 2

    我正在尝试创建curryfunction可以应用于任何函数并返回另一个函数,并应用其中一个参数。我想要的属性:如果函数只有一个参数,curry函数应该返回值:FA);curry(f,x)=f(x);如果函数有很多参数currey应该重新运行curried函数:g(a1,a2,..,aN);curry(g,x)=g2(a2,..,aN):g2(a2,..aN)=g(x,a2,...,aN)柯里化(Currying)函数的长度属性应该“按需”工作g.length=N=>curry(g,x).length=N-1PrototypeFramework中有一些curry的实现,并在oneblog

  10. 函数柯里化详解 - 2

    函数柯里化详解什么是函数柯里化函数柯里化示例实现一个函数,将普通函数柯里化经典面试题函数柯里化应用bind方法是函数柯里化应用的经典场景函数柯里化的优缺点参考什么是函数柯里化柯里化(Currying)又称部分求值,一个柯里化的函数首先会接收一些参数,接收了这些参数后,该函数并不会立即求值,而是继续返回另外一个函数,刚才传入的参数在函数形成的闭包中被保存起来。待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。柯里化是一种函数的转换,它是指将一个函数从可调用的f(a,b,c)转换为可调用的f(a)(b)(c)或者f(a,b)(c)或者f(a)(b,c)通俗的来说:固定部分参数,

随机推荐