Kotlin 并发编程艺术Kotlin专题禅与计算机程序设计艺术

Kotlin(十七)函数式编程<1>

2021-02-25  本文已影响0人  zcwfeng

前言:函数式编程分为狭义和广义两个方面
狭义函数式编程,有着非常严格的标准,只通过纯函数编程,不允许有副作用,所有的数据结构都是不可以改变的。

广义的函数式编程,不强调的都是纯函数。常见的函数式的语言特性:

纯函数和引用透明性

sealed class Format
data class Print(val text: String) : Format()
object Newline : Format()
val string = listOf<Format>(Print("Hello"),
    Newline, Print("Kotlin"))
fun unsafeInterpreter(str:List<Format>){
    str.forEach {
        when(it){
            is Print -> print(it.text)
            is Newline -> println()
        }
    }
}

unsafeInterpreter,引入了副作用

1.缺乏可测试性。如果变更,添加不是print而是写数据库相关方法,如果测试的时候,就会麻烦。

2.难易组合复用。内部混合了字符串格式转化逻辑,如果这里不是打印操作,而是数据库操作,就不能当做字符串转换功能使用。

稍微改动一下,举个例子说明:

fun stringInterpreter(str:List<Format>)
        = str.fold(""){fullText,s ->
    when(s){
        is Print -> fullText + s.text
        is Newline ->fullText + "\n"
    }
}

函数返回字符串结果,无论测试还是复用,都有所提升

基本法则:引用透明性
一个表达式在程序中,可以被它等价的值替换,而不影响结果

一个函数具备引用透明性,内部行为不会改变外部状态

近似数学中的等式推理

纯函数与局部可变性

引用透明不是说不可变,而是局部可变,而整体调用外面是个黑盒,结果是一致的。

fun foo(x:Int):Int{
    var y = 0
    y = y + x
    return y
}

foo具备纯函数f(x)->y.

副作用,在一定的抽象概念,并不绝对没有副作用,即使纯函数,也会使用内存,占用cpu

纯函数具有局限性random随机函数结果不一致都是不同的,不是纯函数

代换模型与惰性求值

错误的例子StackOverflowError 死循环

fun f1(x:Int,y:Int) = x
fun f2(x:Int):Int = f2(x)
  1. 应用序和正则序

kotlin中会先对f2(2) 进行求值,所以会导致死循环
然而如Hashell这种老的纯函数语言,会先调用f1(1,y),因为用不到y所以不会对f2(2)求值

  1. 惰性求值
    模拟一下
    比如针对println,他是一个非纯函数,改造让他"lazy"
fun lazyPrintln(msg:String) = { println(msg)}

当我们执行 lazyPrintln("I am IO operation"),
他仅仅返回一个可执行的println是惰性的,也是可以替代的。

上一篇 下一篇

猜你喜欢

热点阅读