博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
函数式编程----lambda演算
阅读量:5258 次
发布时间:2019-06-14

本文共 3406 字,大约阅读时间需要 11 分钟。

一 概念

函数式编程Functional programming),又称泛函编程,是一种,它将电脑运算视为上的计算,并且避免以及数据。函数编程语言最重要的基础是 (lambda calculus)。而且λ演算的函数可以接受函数当作输入(引数)和输出(传出值)。代表语言haskell,erlang,lisp等

特点:

(1)函数式编程经常使用。

(2)纯函数式的程序不可和无()。因为函数式程序设计语言没有,函数没有,编写出的程序可以利用、和在运行时和编译时得到大量。

(3)惰性求值

 (4) 高阶函数

(5)一切皆函数

缺点:速度和空间上的顾虑

函数式编程常被认为严重耗费在CPU和存储器资源。主因有二:

  • 早期的函数式编程语言实现时并无考虑过效率问题。
  • 非函数式编程语言为求提升速度,会在某些部分放弃边界检查或垃圾回收等功能。

亦为语言如增加了额外的管理工作。

二  λ演算 

λ演算lambda calculus)是一套用于研究定义、函数应用和
Lambda演算被称为最小的通用程序设计语言。它包括一条变换规则(变量替换)和一条函数定义方式,Lambda演算之通用在于,任何一个可计算函数都能用这种形式来表达和求值。因而,它是等价于的。尽管如此,Lambda演算强调的是变换规则的运用,而非实现它们的具体机器。可以认为这是一种更接近软件而非硬件的方式。

形式化定义

所有的lambda表达式可以通过下述以范式表达的描述:

  1. <expr> ::= <identifier>
  2. <expr> ::=(λ<identifier> .<expr>)
  3. <expr> ::=(<expr> <expr>)
例如:λx y.x+y

头两条规则用来生成函数,而第三条描述了函数是如何作用在参数上的。

如下假定保证了不会产生歧义:(1)函数的作用是左结合的,和(2)lambda操作符被绑定到它后面的整个表达式。例如,表达式 (λx.x x)(λy.y) 可以简写成λ(x.x x) λy.y 。

三 lambda演算中的算术

1   邱奇数

Church 编码是把数据和运算符嵌入到 内的一种方式,最常见的形式是 Church 数,它是使用 lambda 符号的自然数的表示法。这种方法得名于 ,他首先以这种方法把数据编码到 lambda 演算中。

在其他符号系统中通常被认定为基本的项(比如整数、布尔值、有序对、列表和 tagged unions)都被映射到使用 Church 编码的;根据我们知道任何可计算的运算符(和它的运算数)都可以用 Church 编码表示。

很多学数学的学生熟悉集合的;Church 编码是定义在 而不是自然数上的等价运算。

Church 数

Church 数是在 Church 编码下的的表示法。表示自然数 n 的是把任何其他函数 f 映射到它的 n 重 f^n = f \circ f \circ \ldots \circ f 的函数。

定义

Church 数 012, ... 在 中被定义如下:

0 ≡ λf.λx. x
1 ≡ λf.λx. f x
2 ≡ λf.λx. f (f x)
3 ≡ λf.λx. f (f (f x))
...
n ≡ λf.λx. fn x
...

就是说,自然数 n 被表示为 Church 数 n,它对于任何 lambda-项 F和 X 有着性质:

n F X  Fn X

使用 Church 数的计算

在 lambda 演算中,数值函数被表示为在 Church 数上的相应函数。这些函数在大多数函数式语言中可以通过 lambda 项的直接变换来实现(服从于类型约束)。

加法函数 plus(m,n)=m+n 利用了恒等式 f^{(m+n)}(x)=f^m(f^n(x))

plus ≡ λm.λn.λf.λx. m f (n f x)

后继函数 succ(n)=n+1 于 (plus 1)。

succ ≡ λn.λf.λx. f (n f x)

乘法函数 times(m,n)=m*n 利用了恒等式 f^{(m*n)} = (f^m)^n

mult ≡ λm.λn.λf. n (m f)

指数函数 exp(m,n)=m^n 由 Church 数定义直接给出。

exp ≡ λm.λn. n m

前驱函数 pred(n) = \begin{cases} 0 & \mbox{if }n=0, \\ n-1 & \mbox{otherwise}\end{cases} 通过生成每次都应用它们的参数 g 于 f 的 n 重函数复合来工作;基础情况丢弃它的 f 复本并返回 x

pred ≡ λn.λf.λx. n (λg.λh. h (g f)) (λu. x) (λu. u)

Church 布尔值

Church 布尔值是布尔值的 Church 编码。布尔值被表示为两个参数的函数,它得到这两个参数中的一个。

中的形式定义:

true ≡ λa.λb. a
false ≡ λa.λb. b

从Church 布尔值推导来的布尔算术的函数:

and ≡ λm.λn.λa.λb. m (n a b) b
or ≡ λm.λn.λa.λb. m a (n a b)
not ≡ λm.λa.λb. m b a

有序对

有序对(2-元组)数据类型可以用TRUEFALSEIF来定义。

CONS := λx y.λp.IF p x y
CAR := λx.x TRUE
CDR := λx.x FALSE

链表数据类型可以定义为,要么是为空列表保留的值(e.g.FALSE),要么是CONS一个元素和一个更小的列表。

递归

是使用函数自身的函数定义;在表面上,lambda演算不允许这样。但是这种印象是误解。考虑个例子,函数f(n)递归的定义为

f(n):= if n = 0 then 1 else n·f(n-1)

在lambda演算中,你不能定义包含自身的函数。要避免这样,你可以开始于定义一个函数,这里叫g,它接受一个函数f作为参数并返回接受n作为参数的另一个函数:

g := λf n.(if n = 0 then 1 else n·f(n-1))

函数g返回要么常量1,要么函数fn-1的n次应用。使用ISZERO谓词,和上面描述的布尔和代数定义,函数g可以用lambda演算来定义。

但是,g自身仍然不是递归的;为了使用g来建立递归函数,作为参数传递给gf函数必须有特殊的性质。也就是说,作为参数传递的f函数必须展开为调用带有一个参数的函数g -- 并且这个参数必须再次f函数!

换句话说,f必须展开为g(f)。这个到g的调用将接着展开为上面的阶乘函数并计算下至另一层递归。在这个展开中函数f将再次出现,并将被再次展开为g(f)并继续递归。这种函数,这里的f = g(f),叫做g的不动点,并且它可以在lambda演算中使用叫做悖论算子不动点算子来实现,它被表示为Y -- :

Y = λg.(λx.g(x x))(λx.g(x x))

在lambda演算中,Y gg的不动点,因为它展开为g(Y g)。现在,要完成我们对阶乘函数的递归调用,我们可以简单的调用 g(Y g)n,这里的n是我们要计算它的阶乘的数。

比如假定n = 5,它展开为:

(λn.(if n = 0 then 1 else n·((Y g)(n-1)))) 5
if 5 = 0 then 1 else 5·(g(Y g,5-1))
5·(g(Y g)4)
5·(λn.(if n = 0 then 1 else n·((Y g)(n-1))) 4)
5·(if 4 = 0 then 1 else 4·(g(Y g,4-1)))
5·(4·(g(Y g)3))
5·(4·(λn.(if n = 0 then 1 else n·((Y g)(n-1))) 3))
5·(4·(if 3 = 0 then 1 else 3·(g(Y g,3-1))))
5·(4·(3·(g(Y g)2)))
...

等等,递归的求值算法的结构。所有递归定义的函数都可以看作某个其他适当的函数的不动点,因此,使用Y所有递归定义的函数都可以表达为lambda表达式。特别是,我们现在可以明晰的递归定义自然数的减法、乘法和比较谓词。

四 各种数据结构

各种数据结构的表示,例如,线性表,树,快排等的实现。请参考byvoid同学的讲稿:

本文总结摘抄自:1 函数式编程

2 lambda演算 

3邱奇数 

4  byvoid同学的讲稿:

5  函数式编程初探 -阮一峰: 

转载于:https://www.cnblogs.com/catkins/archive/2012/11/14/5270699.html

你可能感兴趣的文章
笔记本设置无线热点
查看>>
awk算术运算一例:统计hdfs上某段时间内的文件大小
查看>>
h.264 Mode Decision
查看>>
面向对象进阶(反射)
查看>>
《基于B/S中小型超市进销存管理系统的研究与设计》论文笔记(十六)
查看>>
主数据0
查看>>
HDU2001
查看>>
sql三维数据
查看>>
iOS-id类型
查看>>
ReactNative--View组件
查看>>
C#对.zip 存档读取和写入【转】
查看>>
zabbix图中出现中文乱码问题
查看>>
天眼系统的计划和日程管理
查看>>
linux c 获取系统时间
查看>>
day 09 课后作业
查看>>
白话Redis分布式锁
查看>>
Pandas常用操作方法
查看>>
L2-002. 链表去重(模拟)
查看>>
《linux c编程指南》学习手记2
查看>>
【poj3690】Constellations 哈希
查看>>