学习函数式编程的大图(big map)/鸟瞰图,并在没有掌握Scheme的各种语言细节之前,给出Scheme代码。这意味着我们不需要看懂源代码,而是将这里的介绍作为后续学习的大图,使自己知道身在何处;
1930s初,普林斯顿大学的逻辑学家阿伦佐·丘奇 (Alonzo Church,1903-1995) 开发出了一种新的形式系统(formal system),即拉姆达运算/演算 (λ-calculus 、lambda calculus ,lambda即希腊字母λ)。
λ运算的核心是λ表达式,以此形成函数定义、函数应用和递归的形式系统。当使用λ表达式定义出布尔值、数值和各种基本操作符等语言元素后,就能够形成一种编程语言,所以,λ运算是函数式编程语言共同的祖先,典型代表是Lisp(Scheme)、ML、Haskell和Erlang等等。
由于任何一个可计算函数都能用λ运算来表达和求值,因而它等价于图灵机。
0.1.1λ表达式
普通的数学函数如f(x)=x+1,功能是给其参数x加上1。为了将数学函数表示成计算机常用的表达式,可以换一种写法:
λx.( x+1),读成“对于参数x,x+1”(假定操作符+已经被定义)。丘奇选择了λ,因此各种相关计算称为λ演算。
各种编程语言,也引入了λ表达式。例如:
C#语言:(x) =>{ return x+1; }
Java语言:(x) ->{ return x+1; }
Scheme语言:(lambda (x) (+ x 1))
1. λ表达式的定义
λ表达式极其简洁,由变量、两个抽象符号λ和.(即点),以及括号( )组成。合法的λ表达式的递归定义如下:
- 变量x是一个λ表达式。
- 函数抽象:W是参数为变量x的λ表达式,则λx.W是λ表达式。这种表达式给出了一个函数的定义:W是函数体,形参就是变量x。
λx.( x+1)
λx. λy. ( x+y) ;;;表示 λx. (λy. ( x+y))
- 函数应用:有了f(x)=x+1,自然需要计算f(2),即给函数一个(实际)参数进行求值。A、B是λ表达式,则 (A B) 也是λ表达式,表示将实参B带入函数A中。
通常,编程语言会提供内置的基本函数,如各种操作符。操作符的应用“是一种”函数应用,从λ表达式的递归定义的角度,“函数应用”规则可以得更直接的一条规则:
- 操作符和λ表达式组成的表达式,是λ表达式。如x+1
下面是一些λ表达式的例子:
(最简单的)x、y、
(函数抽象)λx.x、λx.y、
(函数应用)λx.x y、(x y)、λx. (x y)……
2.λ表达式的特点
从λ表达式的定义,可以引申出它的两个特点:
- 匿名函数。数学函数如f(x)=x+1或λ表达式如λx.( x+1),描述了一个计算过程;为该函数命名,是程序员的事情。
- 每个函数只有一个输入参数,如λn. λm.λf.λx. ((n f) (++ m) )。编程时函数可以有一个参数列表,逻辑学家 Haskell Curry证明可以将一个拥有多个参数的函数转化为只有一个参数的多个函数的连续调用,这一转化过程称为对拥有多个参数的函数的currying/柯里化。
3.通过丘奇数,熟悉λ演算的α-变换和β简化。