Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
为什么要柯里化(why-curry-helps)slide http://git.io/why-curry-helps 📈

还记得 Haskell Curry吗,

多巧啊, 人家姓 Curry 名 Haskell, 难怪 Haskell 语言会自动柯里化, 呵呵. 但是不奇怪吗, 为什么要柯里化呢. 为什么如此重要导致 Haskell 会默认自动柯里化所有函数, 不就是返回一个部分配置好的函数吗.

我们来看一个 Haskell 的代码.

max 3 4
(max 3) 4

结果都是4, 这有设么用呢.

这里看不出来, 放到高阶函数试试. 什么? 看不懂天书 Haskell, 来看看 JavaScript 吧.

我们来解一个问题

1. 写一个函数, 可以连接字符数组, 如 f(['1','2']) => '12'

好吧,如果不用柯里化, 怎么写? 啊哈 reduce

var concatArray = function(chars){
  return chars.reduce(function(a, b){
  	return a.concat(b);
  });
}
concat(['1','2','3']) // => '123'

很简单,对吧.

2. 现在我要其中所有数字加1, 然后在连接

var concatArray = function(chars, inc){
  return chars.map(function(char){
  	return (+char)+inc + '';
  }).reduce(function(a,b){
      return a.concat(b)
  });
}
console.log(concatArray(['1','2','3'], 1))// => '234'

3. 所有数字乘以2, 再重构试试看

var multiple = function(a, b){
  return +a*b + ''
}
var concatArray = function(chars, inc){
  return chars.map(function(char){
  	return multiple(char, inc);
  }).reduce(function(a,b){
      return a.concat(b)
  });
}
console.log(concatArray(['1','2','3'], 2)) // => '246'

是不是已经看出问题了呢? 如果我在需要每个数字都减2,是不是很麻烦呢.需要将map 参数匿名函数中的 multiple 函数换掉. 这样一来concatArray就不能同时处理加, 乘和减? 那么怎么能把他提取出来呢? 来对比下柯里化的解法.

柯里化函数接口

var multiple = function(a){
  return function(b){
    return +b*a + ''
  }
}

var plus = function(a){
  return function(b){
    return (+b)+a + ''
  }
}
var concatArray = function(chars, stylishChar){
  return chars.map(stylishChar)
    .reduce(function(a,b){
      return a.concat(b)
  });
}
console.log(concatArray(['1','2','3'], multiple(2)))
console.log(concatArray(['1','2','3'], plus(2)))

有什么不一样呢

  1. 处理数组中字符的函数被提取出来, 作为参数传入
  2. 提取成柯里化的函数, 部分配置好后传入, 好处显而易见, 这下接口非常通畅 无论是外层调用
concatArray(['1','2','3'], multiple(2))

还是内部的 map 函数

chars.map(stylishChar)

这些接口都清晰了很多, 不是吗

这就是函数式的思想, 用已有的函数组合出新的函数, 而柯里化每消费一个参数, 都会返回一个新的部分配置的函数, 这为函数组合提供了更灵活的手段, 并且使得接口更为流畅.

再加上自动柯里化的库 ramda, 简直就完美了

var multiple = ramda.curry(function(a, b){
  return +b*a + ''
})
var plus = ramda.curry(function(a, b){
  return (+b)+a + ''
})

JS Bin<script src="http://static.jsbin.com/js/embed.js"></script>

Analytics

@dandananddada

This comment has been minimized.

Show comment Hide comment
@dandananddada

dandananddada Oct 20, 2015

66666666

66666666

@jackhutu

This comment has been minimized.

Show comment Hide comment
@jackhutu

jackhutu Nov 30, 2015

concat(['1','2','3']) // => '123' 应该改为 concatArray(['1','2','3']) // => '123'

concat(['1','2','3']) // => '123' 应该改为 concatArray(['1','2','3']) // => '123'

@zjien

This comment has been minimized.

Show comment Hide comment
@zjien

zjien Jan 30, 2016

噢,柯里化就是把函数的一部分再提取出来,然后把这一部分配置好再作为一个函数返回给上一层函数,我的理解对吗?

zjien commented Jan 30, 2016

噢,柯里化就是把函数的一部分再提取出来,然后把这一部分配置好再作为一个函数返回给上一层函数,我的理解对吗?

@Wangbaogang

This comment has been minimized.

Show comment Hide comment
@Wangbaogang

Wangbaogang Feb 29, 2016

恩恩,学习了

恩恩,学习了

@flftfqwxf

This comment has been minimized.

Show comment Hide comment
@flftfqwxf

flftfqwxf Jul 9, 2016

但是 柯里化,如果是自己的代码还好,如果是看别人的代码,什么时候返回什么函数,在复杂的逻辑里,很容易搞晕,感觉不是特别环境下,用处没有宣传的那么大,反而造成认知成本

但是 柯里化,如果是自己的代码还好,如果是看别人的代码,什么时候返回什么函数,在复杂的逻辑里,很容易搞晕,感觉不是特别环境下,用处没有宣传的那么大,反而造成认知成本

@Tomatoo

This comment has been minimized.

Show comment Hide comment
@Tomatoo

Tomatoo Mar 25, 2017

concatArray不能称作科里化的函数吧,因为你只传一个参数过去之后并不能返回一个函数。我觉得concatArray只是普通的高阶函数而已。

Tomatoo commented Mar 25, 2017

concatArray不能称作科里化的函数吧,因为你只传一个参数过去之后并不能返回一个函数。我觉得concatArray只是普通的高阶函数而已。

@linjinxing

This comment has been minimized.

Show comment Hide comment
@linjinxing

linjinxing Apr 4, 2017

mark

mark

@libchaos

This comment has been minimized.

Show comment Hide comment
@libchaos

libchaos Sep 11, 2017

@Tomatoo you are right

@Tomatoo you are right

@zhangfaliang

This comment has been minimized.

Show comment Hide comment
@zhangfaliang

zhangfaliang Sep 11, 2017

学习了,柯里化和高阶有什么区别

学习了,柯里化和高阶有什么区别

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment