编程范式和函数式编程

编程范式

函数式编程是一种编程范式,我们常见的编程范式有

  • 命令式编程(Imperative programming)
  • 函数式编程
  • 逻辑式编程

命令式编程

  • 命令式编程是面向计算机硬件的抽象,有变量(对应着存储单元),赋值语句(获取,存储指令),表达式(内存引用和算术运算)和控制语句(跳转指令)
  • 一句话,命令式程序就是一个冯诺依曼机的指令序列
  • 常见的面向对象编程也是一种命令式编程

函数式编程

  • 函数式编程是面向数学的抽象,将计算描述为一种表达式求值
  • 一句话,函数式程序就是一个表达式。

区别

  • 函数式编程关心数据的映射,命令式编程关心解决问题的步骤
  • 函数式编程关心类型(代数结构)之间的关系,命令式编程关心解决问题的步骤

函数式编程的本质

函数式编程中的函数这个术语不是指计算机中的函数,而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如 sqrt(x) 函数计算 x 的平方根,只要 x 不变,不论什么时候调用,调用几次,值都是不变的。

  • 在函数式语言中,函数作为一等公民,可以在任何地方定义,在函数内或函数外,可以作为函数的参数和返回值,可以对函数进行组合。

  • 纯函数式编程语言中的变量也不是命令式编程语言中的变量,即存储状态的单元,而是代数中的变量,即一个值的名称。变量的值是不可变的(immutable),也就是说不允许像命令式编程语言中那样多次给一个变量赋值。比如说在命令式编程语言我们写“x = x + 1”,这依赖可变状态的事实,拿给程序员看说是对的,但拿给数学家看,却被认为这个等式为假。

  • 函数式语言中的条件语句,循环语句也不是命令式编程语言中的控制语句,而是函数的语法糖,比如在Scala语言中,if else不是语句而是三元运算符,是有返回值的。

严格意义上的函数式编程意味着不使用可变的变量,赋值,循环和其他命令式控制结构进行编程。

从理论上说,函数式语言也不是通过冯诺伊曼体系结构的机器上运行的,而是通过λ演算来运行的,就是通过变量替换的方式进行,变量替换为其值或表达式,函数也替换为其表达式,并根据运算符进行计算。λ演算是图灵完全(Turing completeness)的,但是大多数情况,函数式程序还是被编译成(冯诺依曼机的)机器语言的指令执行的。

函数式编程的好处

由于命令式编程语言也可以通过类似函数指针的方式来实现高阶函数,函数式的最主要的好处主要是不可变性带来的。没有可变的状态,函数就是引用透明(Referential transparency)的和没有副作用(No Side Effect)。

  • 一个好处是,函数即不依赖外部的状态也不修改外部的状态,函数调用的结果不依赖调用的时间和位置,这样写的代码容易进行推理,不容易出错。这使得单元测试和调试都更容易。

  • 不变性带来的另一个好处是:由于(多个线程之间)不共享状态,不会造成资源争用(Race condition),也就不需要用锁来保护可变状态,也就不会出现死锁,这样可以更好地并发起来,尤其是在对称多处理器(SMP)架构下能够更好地利用多个处理器(核)提供的并行处理能力。

总结

  • 函数式编程是给软件开发者提供的另一套工具箱,为我们提供了另外一种抽象和思考的方式。
  • 函数式编程也有不太擅长的场合,比如处理可变状态和处理IO,要么引入可变变量,要么通过Monad来进行封装(如State Monad和IO Monad)

你可能感兴趣的:(编程补充)