λ

关于λ经常会听到λ演算和λ表达式这两名词,其实分别对应的是理论和应用两个维度。它们的关系可以类比于质能方程和原子弹。

λ演算

数学家阿隆佐-邱奇在20世纪30年代提出λ演算,作为数学基础研究的一部分。那个年代,数学界有个领袖,叫希尔伯特(一人之力将葛根廷大学建设为当时数的世界中心)。他提出将数学定理机械化,这样机器就可以通过形式语言推理出大量新定理(AI的味道?)。比他小几岁的图灵和邱奇都受到他这一思潮影响,并从不同的角度解决了这同一个问题。理论上,图灵机和λ演算,都可以模拟出我们今天所有的程序。

λ演算是一种形式系统(formal system),什么是形式系统呢?大家知道,数学语言是是可以脱离现实而存在的——大家把数学想成了一种符号游戏,脱离生活常识,从公理开始,进行大量的推导和证明——最终产生一个系统,里面有公理、定理、推论、猜想…上述这种自成体系,有公理又有推理证明方法的体系,称为形式系统。而形式系统需要语言去描绘,这种语言就是形式语言(formal language)。邱奇希望用λ演算来表达有关数学的一切,比如用一系列函数来表达自然数,符号,定理等。

本质上图灵机和λ演算是做同一件事情,也是可以互相转换的。

Lambda表达式

区别于λ演算中的λ表达式,编程中提到的Lambda表达式,一般就指一个匿名函数。为什么要用匿名函数,对于一个只用一次的函数,匿名使用当然更简洁方便。eg,给view一个点击事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
// java 8以前
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("click","-----");
}
});

// java 8用上Lambda的匿名函数
view.setOnClickListener(v -> Log.d("click","-----"));

// kotlin 版本
view.setOnClickListener { Log.d("click", "-----") }

那种写法更好一目了然,对吧。

所以在编程中使用Lambda表达式,可以让代码更符合直觉,写法清晰简练自然也带来更好的维护性。

好的维护性程序员不挠头,也可以推导出Lambda表达式具有程序员发际线友好特性。

λ与编程语言

图灵机奠定了计算机基础,那能和它等价转化的λ演算呢?实际上λ演算在数学哲学[2]语言学[3][4]计算机科学[5]中都有许多应用。它在编程语言理论中占有重要地位,函数式编程实现了λ演算支持。λ演算在范畴论中也是一个研究热点。

大部分编程语言都或多或少受λ演算所启发和影响,尤其是函数式友好语言(Lisp,ML,Haskell,Scala,C++,Java8 Lambda)。

Java8 实现Lambda的方式是通过invokedynamic指令,运行时调用LambdaMetafactory.metafactory动态的生成内部类,在内部类里调用原class的静态方法快来实现的。

应用

在Java中能被Lambda改写的前提必须是一个函数接口(指内部只有一个抽象方法的接口)。

1
2
3
4
@FunctionalInterface
public interface ConsumerInterface<T>{
void accept(T t);
}

上面代码中的@FunctionalInterface不是必须而是可选的,但加上该标注编译器会帮你检查接口是否符合函数接口规范。就像加入@Override标注会检查是否重载了函数一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//1,点击事件
view.setOnClickListener(v -> Log.d("click","-----Hello"));

//2,线程方法
Runnable run = () -> Log.d("----Hello World");

//3,Collection (list)操作
ArrayList<String> list = new ArrayList<>(Arrays.asList("hello", "world"));
list.forEach(it -> Log.d("tag", "---" + it));
list.removeIf(it -> it.startsWith("h"));
list.sort((o1, o2) -> o1.length() - o2.length());
//kotlin
val list = listOf("hello", "world")
list.forEach { print(it) }
list.filterNot { it.startsWith("h") }
list.sortedWith(Comparator { o1, o2 -> o1.length - o2.length })

//4, Collection (map)操作
Map<String, String> map = new HashMap<>();
map.forEach((k, v) -> Log.d("tag", "---" + k + v));
map.replaceAll((k, v) -> v.toUpperCase());
map.merge("key", "value", (v1, v2) -> v1 + v2);
//kotlin
val map = HashMap<String, String>()
map.forEach { (t, u) -> print("----$t $u") }
map.replaceAll { t, u -> u.toUpperCase() }
map.filter { (t, u) -> t.startsWith("h") }

参考

https://zh.wikipedia.org/wiki/%CE%9B%E6%BC%94%E7%AE%97

https://zhuanlan.zhihu.com/p/30510749