函数式编程的几个特征

函数式编程

函数式编程属于声明式编程的一种,将计算描述为数学函数的求值,但是并没有准确的定义,只是一系列理念,并不需要严格准守,可以理解为函数式编程把程序看做是数学函数,输入的是自变量,输出因变量,通过表达式完成计算。现在越来越多的命令式语言支持部分的函数式编程特性,比如java8中的lambda。

lambda表达式

Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数

python中的lambda表达式

foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
print map(lambda x: x * 2 + 10, foo)
#[14, 46, 28, 54, 44, 58, 26, 34, 64]

javascript

var foo = [2, 18, 9, 22, 17, 24, 8, 12, 27];
foo.map((v) = > {
  return x * 2;
})
//[14, 46, 28, 54, 44, 58, 26, 34, 64]

erlang

Foo = [2, 18, 9, 22, 17, 24, 8, 12, 27],
lists:map(fun(X) -> X *2 end,Foo).

java8

List foo = Arrays.asList(2, 18, 9, 22, 17, 24, 8, 12, 27);
foo.stream().map((cost) -> cost * 2);

使用lambda表达式的好处是减少了代码量,而且使程序更加灵活易读,若不使用lambda表达式,对于以上代码,若需要将每个集合里的数变为原来的3倍,那么必须重新编写一套新的代码,使用lambda表达式可以大大增加代码的灵活性。

高阶函数

在函数式编程中,函数作为一等公民,就是说函数的行为和普通变量没有区别,可以作为函数参数进行传递,也可以在函数内部声明一个函数,那么外层的函数就被称作高阶函数。

javascript

function maps(l,cb){
  //函数内部定义函数
  let func1 = () =>{console.log("function test1")};
  function func2(){
    console.log("function test2");
  }
  
  let temp = [];  
  for(let i = 0;i {
  return v * 2;
})
console.log(re);
// re : [2,4,6,8,10]

go

func maps(l []int,cb func(v int) int){
    for i:=0;i

柯里化

柯里化(英语:Currying),把接受多个参数的函数变换成接受一个单一参数的函数,返回接受余下的参数并且返回结果的新函数。

比如说在javascript中

//不使用柯里化
function add(a,b){
  return a+b;
}
add(1,2);

//currying
function add(a){
  return (b) =>{
     return a+b;
  }
}
add(1)(2)

柯里化的好处是减少了函数的参数个数,并且模块化了每步计算,与设计模式中的适配器模式(将一个接口转换为另一个接口)类似,并且柯里化的应用之一"惰性求值"也是函数式编程的一个重要特性

一次赋值

函数式编程要求所有的变量都是常量(这里所用的变量这个词并不准确,只是为了便于理解),erlang是其中的典型语言,虽然许多语言支持部分函数式编程的特性,但是并不要求变量必须是常量。这样的特性提高了编程的复杂度,但是使代码没有副作用,并且带来了很大的一个好处,那就是大大简化了并发编程。就用java来说吧,java中最常用的并发模式是共享内存模型,依赖于线程与锁,若代码编写不当,会发生死锁和竞争条件,并且随着线程数的增加,会占用大量的系统资源。在函数式编程中,因为都是常量,所以根本就不用考虑死锁等情况。为什么说一次赋值提高了编程的复杂度,既然所有变量都是常量,那么我们没办法更改一个变量的值,循环的意义也就不大,所以haskell与erlang中使用递归代替了循环。

命令式语言中遍历一个数组
c语言

int l[5] = {1,2,3,4,5};
int i = 0;
for(;i<5;i++)
{
  //some action
}

erlang

loop([]) -> [];
loop([H|T]) ->
  % some action with   H
  loop(T).

test() ->
  loop([1,2,3,4,5]).

%在erlang终端中执行test函数

闭包

闭包是指那些能够访问独立(自由)变量的函数 (变量在本地使用,但定义在一个封闭的作用域中)。换句话说,这些函数可以“记忆”它被创建时候的环境。可以看stackoverflow上的大佬怎么回答的。

javascript代码

function sayHello() {
    let i = 0;
    return () =>{
        return i ++;
    }
}
let t = sayHello();
console.log(t(),t(),t());//0,1,2
//闭包会保持其对外部变量的引用

你可能感兴趣的:(函数式编程的几个特征)