Blog - wingsico

前言

最近开始学习函数式编程,对函数式编程有了更多的一点点认识,对函数的curry接触了一点点,以此作为记录,写下当前感悟

思考

先来看一个常见的需求:

现给定一个字符串: const STRING = “This is the mid day show with Cheryl Waters” 请将空格替换成”-“

这是一个很简单的需求,很自然的写下:

1
2
3
4
5
const replaceSpaceToStrike = (str) => {
return str.replace(/ /g, '-')
}

replace(STRING)

或者是写个更具有拓展性的函数:

1
2
3
4
5
const replace = (reg, replacement, str) => {
return str.replace(reg, replacement)
}

replace(/\s+/g, '-', STRING)

发现参数多而杂乱。那么把它curry化我们应该如何去写:

1
2
3
4
5
6
7
const replace = what => replacement => str => str.replace(what, replacement)

const noSpaces = replace(/\s+/g)

const cenosred = noSpaces('-')

cenosred(STRING)

这里可以看到 curry 化在完成最终需求之前生成了许多 curry 帮助函数, 这里表明了一种 预加载函数 的能力,通过传递一到两个参数调用函数,就能得到一个记住了这些参数的新函数。 相比于之前的解决方案,它需要更多的代码,但只需要参入一部分参数,就能的到一个新的函数。相对于之前的方案,它更加灵活,同时减少了同时传参的个数。 这个例子可能没有突出函数式 curry 化的优点,再举一个例子:

1
const getChildren = x => x.childNodes // 获得一个节点的子节点

这是针对一个元素的函数, 利用curry化,我们可以很容易扩展到数组:

1
2
const map = f => arr => arr.map(f)
const getAllChildren = map(getChildren)

通常我们不定义直接操作数组的函数,因为只需内联调用 map(getChildren) 就能达到目的。这一点同样适用于 sortfilter 以及其他的 高阶函数(higher order function)(高阶函数:参数或返回值为函数的函数)。

小结

curry 函数用起来非常得心应手,使用它简直就是一种享受。它堪称手头必备工具,能够让函数式编程不那么繁琐和沉闷。 通过简单地传递几个参数,就能动态创建实用的新函数;而且还能带来一个额外好处,那就是保留了数学的函数定义,尽管参数不止一个。 此外,我们还可以引入 lodashramda 中的 curry 函数,帮助我们更好的实现curry化。

 评论