Scala Learning(4): Currying柯里化的推演

本文展示加法和乘法的两个例子,最后使用MapReduce的思想把两者统一成一个带Currying的表达形式。

从high-order functions推演到Currying

原始方法

def sum(f: Int => Int, a: Int, b: Int): Int =
  if (a > b) 0
  else f(a) + sum(f, a + 1, b)

表示从a到b,把每个int做一次f处理,把所有结果累加起来。

对应”加法”、”立方”、”阶乘”,实现三个funtion

def id(x: Int): Int = x
def cube(x: Int): Int = x * x * x
def fact(x: Int): Int = if (x == 0) 1 else fact(x - 1)

把这三个方法填充到原始的sum方法里,得到三个新方法

def sumInts(a: Int, b: Int) = sum(id, a, b)
def sumCubes(a: Int, b: Int) = sum(cube, a, b)
def sumFactorials(a: Int, b: Int) = sum(fact, a, b)

将前两个简化,把function匿名地传入sum里,得到

def sumInts(a: Int, b: Int) = sum(x => x, a, b)
def sumCubes(a: Int, b: Int) = sum(x => x * x * x, a, b)

写起来更简短一些。

进一步的,我们注意到a: Int,b: Int这俩参数在各个实现里都是从左到右带过去的,可以简化地重新实现原始的sum方法

def sum(f: Int => Int): (Int, Int) => Int = {
  def sumF(a: Int, b: Int): Int =
    if (a > b) 0
    else f(a) + sumF(a + 1, b)
  sumF
}

如此,新的sum方法传入一个f,返回值也是一个function,借助新的sum,上面三个方法可以这样实现

def sumInts = sum(x => x)
def sumCubes = sum(x => x * x * x)
def sumFactorials = sum(fact)

使用如

sumCubes(1, 10) + sumFactorials(10, 20)

本质上就是Currying的形式了,展开是:

def sum(f: Int => Int)(a: Int, b: Int): Int = ...

类型是什么呢?

类型是

(Int => Int) => (Int, Int) => Int

右侧也就是Int,即

Int => Int => Int

Int => (Int => Int)

MapReduce例子

回到加法的例子:

MapReduce例子

回到加法的例子,用Currying的方式改写为:

def sum(f: Int => Int)(a: Int, b: Int): Int =
  if (a > b) 0
  else f(a) + sum(f)(a + 1, b)

用Currying类似写一个乘法:

def product(f: Int => Int)(a: Int, b: Int): Int =
  if (a > b) 1
  else f(a) * product(f)(a + 1, b)

注意到,两者在初始值、else分支的计算处理上有所不同,使用MapReduce的思想把两个计算统一起来:

def mapReduce(f: Int => Int, combine: (Int, Int) => Int, initValue: Int)(a: Int, b: Int) : Int =
  if (a > b) initValue
  else combine(f(a), mapReduce(f, combine, initValue)(a+1, b))

把product套进去,可以表示为

def product(f: Int => Int)(a: Int, b: Int): Int =
  mapReduce(f, (x, y) => x*y, 1)(a, b)

把sum套进去,可以表示为

def sum(f: Int => Int)(a: Int, b: Int): Int =
  mapReduce(f, (x, y) => x+y, 0)(a, b)

全文完 :)

时间: 2025-01-04 09:02:08

Scala Learning(4): Currying柯里化的推演的相关文章

Scheme高阶函数之函数作为返回值暨currying/柯里化

1.4.1currying/柯里化 通常,编程的函数可以有一个参数列表,而λ表达式要求单参数.所以,currying/柯里化--多个参数的函数转化为只有一个参数的多个函数的连续调用,需要函数作为返回值. 有λ表达式,λx. λy. ( 2x+3y) (define (F x y)(+ ( * 2 x) (* 3 y)));;;等价于下面的表示 (define F (lambda ( x y) (+ ( * 2 x) (* 3 y)) ) ) (F 2 3)            → 13 函数F

浅析 JavaScript 中的 函数 currying 柯里化

原文:浅析 JavaScript 中的 函数 currying 柯里化 何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名). 柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果.因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程. 柯里化一个求和函数 按照分步求值,我们看一个

javascript中的函数currying(柯里化) 的理解

首先简要说一下什么是curry化 :它是一种通过把多个参数填充到函数体中,实现将函数转换成一个新的经过简化的(使之接受的参数更少)函数技术.(摘自:精通JavaScrtpt图灵计算机科学丛书-21页) //写一个简单点的 function curry(fn/*function*/ , scope/*object?*/){ //取到除必须参数的其他参数,也就是第二个以后的所有参数,做一个缓存 var args = [].slice.call(arguments , 2); console.log(

currying 柯里化,返回函数

var currying = function(fn){var arg = [].slice.call(arguments,1);//获得除了fn之外的参数.return function(){//返回一个函数var newArgs = arg.concat([].slice.call(arguments));//把旧参数和新参数放在一起 .fn.apply(null,newArgs);//使用所有参数}}; var sayHi = function(){var args = [].slice.

Scala中的柯里化

一.初识Currying柯里化 柯里化(Currying)技术 Christopher Strachey 以逻辑学家 Haskell Curry 命名的(尽管它是 Moses Schnfinkel 和 Gottlob Frege 发明的).它是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术. 简单理解就是改变函数的表达形式但其功能特性不变,这对于第一次接触柯里化的人来讲,这样的一个技术貌似有点“鸡肋”,但如果你有丰富的JS

JS中的柯里化(currying)

何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字命名). 柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果.因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程. 柯里化一个求和函数 按照分步求值,我们看一个简单的例子 var concat3Words = function (a

JavaScript柯里化

什么是柯里化 柯里化允许我们把函数与传递给它的参数结合,产生一个新的函数.[引自<JavaScript语言精髓>,第43页 柯里化] A function is said to be curried when not all arguments have been supplied to the function, so it returns another function that retains the arguments given and expects the remaining

JavaScript 反柯里化

浅析 JavaScript 中的 函数 uncurrying 反柯里化 柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果.因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程.请见我的另一篇博客· 浅析 JavaScript 中的 函数 currying 柯里化 反柯里化 相反,反柯里化的作用在与扩大函数的适用性,使本来作为特定对象所拥有的功能的函数可以

Scala函数柯里化(Currying or Curry)

柯里化(Currying) 把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术. 简单的实现如下: scala> def add(x:Int, y:Int) = x + y add: (x: Int, y: Int)Int 假如我们应用的时候,是这样的:add(1,2) 柯里化函数: scala> def add(x:Int)(y:Int) = x + y Curry化最大的意义在于把多个参数的function等价转化成多