难得今天休息了一天,就一直在睡觉,突然看到群里有人说到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后也有这个概念,这就不多说了,另一个故事了,你应该看到了,我们给三个参数的函数写了个扩展方法,这样我们所有三个参数的函数柯里化就可以直接调这个扩展函数了。
其实柯里化本身很简单,难的是他的概念。
这东西我也是记录一下,现在差不多写完了,收工睡觉了。
谢谢你看到这里看到发牢骚>_<。。。