难得今天休息了一天,就一直在睡觉,突然看到群里有人说到Kotlin的柯里化,正好最近在学习Kotlin,就想要记录一下。想到自己很久没动的博客(懒..不是忙),垂死病中惊坐起,意识到自己不能继续颓废下去了,赶紧爬起来写了这篇博客,也算是新年有个好开始吧。以后尽量把博客捡起来。。。

Koltin是什么语言我也不想多说了,google的推荐让这个东西着实火了一把,我也就怀着好奇心去学了下,因为以前一直写Java(写的时间也不久),确实被Kotlin的扩展函数,重载操作符,空安全给吸引到了,说实话,写了Kotlin,我真的觉得Java在这个时代有点过去式的感觉。。不多说了,看标题就知道我今天要说的是什么了。

###柯里化

这是一个神奇的东西,Java未曾出现过,起码在java8之前(即使是8我觉得也不是标准的Curry,只是像而已),虽然Kotlin没有这个语法糖,但对于可以FP的Kotlin来说,这都不是事。

维基百科这样说道:
在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术.

可能有些人觉得很困惑,确实,对没接触过fp的语言的人来说确实有点难懂。没事,Talk is cheap, show you code.

####举个栗子:
有时候我们想要打印一些东西,于是我们如是写道

1
2
3
4
5
6
7
8
9
10
in:
fun log(tag: String, target: OutputStream, message: Any?) {
target.write("$tag $message\n".toByteArray())
}

fun main(args: Array<String>) {
log("louis", System.out, "what f**k")
}
output:
louis what f**k

一个简单的实现就完成了,但是我们看着不爽啊,这方法调着有点烦人啊(只是个例子,不要较真),于是我们想到了柯里化。

初次修改后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
in:
fun logCurry(tag: String): (target: OutputStream) -> (message: Any?)-> Unit{
return fun (target: OutputStream): (message: Any?) -> Unit {
return fun (message: Any?) {
return target.write("$tag $message\n".toByteArray())
}
}
}

fun main(args: Array<String>) {
logCurry("louis")(System.out)("what f**k")
}

output:
louis what f**k

简单的柯里化函数就完成了,但是这代码,喔吼,不是变得很麻烦了吗,看起来也不简单啊,没事我再改一下。

1
2
3
4
5
6
7
8
9
10
11
12
in:
fun log(tag: String)
= fun (target: OutputStream)
= fun (message: Any?)
= target.write("$tag $message\n".toByteArray())


fun main(args: Array<String>) {
log("louis")(System.out)("what f**k")
}
output:
louis what f**k

这就是把他柯里化的最终版本了,其实也只是利用了fp的范式,看到这里你应该要骂人了,这哪里简单了,没关系,我们写Kotlin,要的就是简单易读(骚),我们不还有扩展函数吗,给这种东西写个柯里化的扩展还不是分分钟吗,仔细看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
in:
fun <P1, P2, P3, R> Function3<P1, P2, P3, R>.curried(): (P1) -> (P2) -> (P3) -> R {
return fun (p1: P1): (P2) -> (P3) -> R {
return fun (p2: P2): (P3) -> R {
return fun (p3: P3): R {
return this(p1, p2, p3)
}
}
}
}

fun main(args: Array<String>) {
::log.curried()("louis")(System.out)("what f**k")
}

::log是method reference(函数引用),java8后也有这个概念,这就不多说了,另一个故事了,你应该看到了,我们给三个参数的函数写了个扩展方法,这样我们所有三个参数的函数柯里化就可以直接调这个扩展函数了。

其实柯里化本身很简单,难的是他的概念。

这东西我也是记录一下,现在差不多写完了,收工睡觉了。

谢谢你看到这里看到发牢骚>_<。。。