Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Functional Programming
Search
runninghack
November 05, 2012
Programming
3
160
Functional Programming
runninghack
November 05, 2012
Tweet
Share
More Decks by runninghack
See All by runninghack
Object Orientation Is a Hoax
runninghack
1
180
Other Decks in Programming
See All in Programming
Create a website using Spatial Web
akkeylab
0
300
「ElixirでIoT!!」のこれまでとこれから
takasehideki
0
370
PostgreSQLのRow Level SecurityをPHPのORMで扱う Eloquent vs Doctrine #phpcon #track2
77web
2
340
datadog dash 2025 LLM observability for reliability and stability
ivry_presentationmaterials
0
110
ReadMoreTextView
fornewid
1
480
iOSアプリ開発で 関数型プログラミングを実現する The Composable Architectureの紹介
yimajo
2
210
git worktree × Claude Code × MCP ~生成AI時代の並列開発フロー~
hisuzuya
1
480
DroidKnights 2025 - 다양한 스크롤 뷰에서의 영상 재생
gaeun5744
3
320
Azure AI Foundryではじめてのマルチエージェントワークフロー
seosoft
0
130
VS Code Update for GitHub Copilot
74th
1
390
Railsアプリケーションと パフォーマンスチューニング ー 秒間5万リクエストの モバイルオーダーシステムを支える事例 ー Rubyセミナー 大阪
falcon8823
4
950
#kanrk08 / 公開版 PicoRubyとマイコンでの自作トレーニング計測装置を用いたワークアウトの理想と現実
bash0c7
1
440
Featured
See All Featured
How to Ace a Technical Interview
jacobian
277
23k
Bash Introduction
62gerente
614
210k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.4k
Making the Leap to Tech Lead
cromwellryan
134
9.3k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Rebuilding a faster, lazier Slack
samanthasiow
82
9.1k
Being A Developer After 40
akosma
90
590k
Typedesign – Prime Four
hannesfritz
42
2.7k
The Invisible Side of Design
smashingmag
299
51k
The Cost Of JavaScript in 2023
addyosmani
51
8.4k
Agile that works and the tools we love
rasmusluckow
329
21k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
44
2.4k
Transcript
函数式编程 Functional Programming
函数式编 程 函数式编 程概述 特点 优点 Lambda Calculus 语法公理 不定点
Y组合子 Lisp语言 初探 语法初探 代码示例
第一节 函数式编程概述 Functional Programming In a Nutshell
• Python -> Ruby 简单 • Java -> C# 简单
• 第一次学FPL 见鬼了!
函数式编程是一种编程范式 • 编程范式是一类典型的编程风格,是指从 事软件工程的一类典型的风格。
主要的编程范式有: • 面向对象 • 命令 • 函数 • 逻辑 •
其他
编程范式对应的计算模型 • 面向对象&&命令 -> 图灵机 • 函数 -> lambda演算 •
逻辑 -> 一阶逻辑
代表语言 • Lisp(强动态类型) – Common Lisp – Scheme • Haskell(纯函数式语言)
• F#(强静态类型) • ML(强静态类型) • Erlang(强动态类型)
函数式编程的特点 1. 函数是"第一等公民― 2. 惰性求值 3. 只用"表达式",不用"语句― 4. 不修改状态,没有―副作用―,引用透明
1. 函数是"第一等公民" • 第一等公民:first-class functions • 函数与其他数据类型一样,处于平等地位
如果要实现一个函数,对两个数根据给 定的操作进行四则运算,这两个数可以 是整数也可以是小数,该如何?
扩展 – 高阶函数 • 函数的参数可以是函数 • 函数的返回值可以是函数
2. 惰性求值(Lazy Evaluation) • 延迟求值特别用于函数式编程语言中。在使用 延迟求值的时候,表达式不在它被绑定到变量 之后就立即求值,而是在該值被取用的时候求 值 • [1..]代表所有自然数
• [1,3..]代表所有奇数 • 代码灵活性(unless逻辑) • 最终优化
3. 只用"表达式",不用"语句" • "表达式" (expression)是 一个单纯的运算 过程,总是有返 回值 • 针对数学模型
• "语句" (statement)是 执行某种操作, 没有返回值 • 针对机器硬件
C# Scheme
4. 不修改状态、没有"副作用" • 函数要保持独立,所有功能就是返回一个 新的值,没有其他行为 • 尤其是不得修改外部变量的值。
C# Scheme
4. 引用透明 • 引用透明(Referential transparency),指 的是函数的运行不依赖于外部变量或"状态", 只依赖于输入的参数 • 任何时候只要参数相同,引用函数所得到 的返回值总是相同的。
函数编程的优点 1. 代码简洁,开发快速 2. 接近自然语言,易于理解 3. 更方便的代码管理 4. 易于"并发编程― 5.
代码的热升级
1. 代码简洁,开发快速 • Paul Graham在《黑客与画家》 一书中写道:同样功能的程 序,极端情况下,Lisp代码的 长度可能是C代码的二十分之 一。
2. 接近自然语言,易于理解 • 函数式编程的自由度很高,可以写出很接 近自然语言的代码。 • 硬件对人透明
3. 更方便的代码管理 • 函数式编程不依赖、也不会改变外界的状 态,只要给定输入参数,返回的结果必定 相同。 • 因此,每一个函数都可以被看做独立单元, 很有利于进行单元测试(unit testing)和除
错(debugging),以及模块化组合。
4. 易于并发编程 • 函数式编程不修改变量,所以根本不存在 ―锁‖线程的问题。 • 想一想:死锁、共享对象、堆栈跟踪、低 级处理器缓存命中率低 • Erlang的使用
5. 代码的热升级 • 函数式编程没有副作用,只要保证接口不 变,内部实现是外部无关的。所以,可以 在运行状态下直接升级代码,不需要重启, 也不需要停机。 • Erlang用于电话系统。
6. 函数式编程很酷(什么,还有6?) • 在黑客圈子里,Java<Perl<Python<Ruby • 越排在后面的语言越像Lisp。
第二节 LAMBDA演算 The Foundation of Functional Programming
函数式编程的起源 - λ演算 • λ演算(lambda calculus)是 一套用于研究函数定义、函 数应用和递归的形式系统。 • 它由Alonzo
Church 和 Stephen Cole Kleene在20世 纪30年代引入
λ演算的语法 使用BNF范式定义: • <expression>::=<name>|<function>|<application> • //函数抽象:用来生成函数 • < function >::=λ
< name >.< expression > • 例: λ x. x+3 • //函数作用:使函数作用于参数 • < application >::=(< expression > < expression >) • 例: λ x. x+3 4 =>7
λ演算的公理 α-置换公理: • λ x y. x+y == λ a
b. a+b β-归约公理: • (λ x y. x+y) a b => a+b
前置知识 - Currying • 为尽量精简,lambda算子只接受一个参数。 • 那怎么处理多个参数呢
前置知识 - Currying • Func<int, Func<int, int>> f = x
=> y => x + y; • int i = f(1)(2); • f 等于这样一个函数,接受一个int参数x, 并返回另一个函数Func<int, int>,这个函 数再接收一个int参数y,且对这个函数的调 用结果是x + y
题外话 – 丘奇数 • 零是 lambda s z . z
• 一是 lambda s z . s z • 二是 lambda s z . s (s z) • …… • lambda s z . s sn z • add = lambda s z x y . x s (y s z)
实现递归 计算n的阶乘: • f (x) = λ x. x <
1 ? 1 : x * f(x - 1) 但是在lambda演算中,f= 只是一个语法糖, 在表达式完成之前没有意义 Lambda演算不直接支持递归,我们需要实现 它
• f (x)= λx. x < 1 ? 1 :
x * f(x - 1) • 无法调用自身,那么就给自身当做参数↓ • 设F(f)(x) = λf λx. x < 1 ? 1 : x * f(x - 1) • 进行currying,F(f)=f,但是F的第一个参数 是什么呢?
• 为了使用F来建立递归函数,作为参数传递 给F的f函数必须有特殊的性质:作为参数传 递的f函数必须展开为调用带有一个参数的 函数F -- 并且这个参数必须再次f函数! • 即f =
F(f),这叫做F的不动点
不动点 • 一阶函数的不动点f(x)=x • 高阶函数的不动点f = F(f) • 如何求F的不动点呢?
Y组合子 • Y组合子是一个高阶函数,它接受一个函数, 返回的是这个函数的不动点 • Y = λ f. (λ
x. f (x x)) (λ x. f (x x))
试试对不对 • Y g = (λf.(λx . f (x x))
(λx . f (x x))) g • Y g = (λx. g (x x)) (λx . g (x x)) • Y g = (λy. g (y y)) (λx . g (x x)) • Y g = g ((λx. g (x x)) (λx . g (x x))) • Y g = g (Y g) 即 Y g = g (Y g)
试着用一下Y组合子 g = λ f n. n==0 1 n *
f(n-1) 则递归函数为g(Y(g)) g(Y(g)) 4 = 4==0 1 4 * Y(g) 3 = 4 * Y(g) 3 = 4 * g(Y(g)) 3 //正是递归!
Y组合子的另一种形式 • Y = λ F. G(G) • 其中 G=
λ self. F(self(self))
强类型的Y组合子
Y组合子的意义 • 给lambda演算添加了一条引理:函数可以 递归 • lambda演算和图灵机完全等价
第三节 SCHEME An Example of Functional Programming
数据结构 - pair • (define p (cons 4 5)) •
=>(4, 5) • 操作: car cdr set-car! set-cdr!
数据结构 - list • (define la (list 1 2 3
4 5)) • 操作:length, list-ref, list-set! • (make-list 5 6)=>(6 6 6 6 6)
函数 • ((lambda (x) (+ x x)) 5) =>10 •
(define add5 (lambda (x) (+ x 5)))
顺序结构 • (begin form1 form2) • 例:(begin (display ―Hello world‖)
(newline))
if 结构 • (if 测试 过程1 过程2) • (if (=
x 0) (display ―is zero‖)(display ―not zero‖))
cond 结构 • (cond ((测试)操作) … (else 操作)) • (define
w (lambda (x) (cond ((< x 0) 'lower) ((> x 0) 'upper) (else 'equal))))
case 结构 • (case (表达式) ((值) 操作)) ... (else 操作)))
• (case (* 2 3) ((2 3 5 7) 'prime) ((1 4 6 8 9) 'composite))
小练习 - factorial • (define factorial (lambda (x) (if (<=
x 1) 1 (* x (factorial(- x 1))))))
• SICP官方版46页
factorial另一种实现 • (define (factorial) (define (iter product counter) //块结构 (if
(> counter n) product (iter (* counter product) (+ counter 1)))) (iter 1 1))
• SICP官方版47页
计算过程:递归 vs 迭代 • 变量不显式存在, 而是隐藏于函数调 用栈 • 函数调用栈的长度 正比于n
• 需要提供变量存储 计算状态的描述 • 计算步骤数正比于 n
递归过程 vs 递归计算过程 • 递归过程是语法形 式上的事实 • factorial的第二种 实现在语法上是递 归的
• 递归计算过程是计 算过程的进展方式 • factorial的第二种 实现在计算过程上 时迭代的
尾递归 • 显然,迭代优于递归,但是诸多语言对于 迭代和递归的实现是相同的 • Scheme等语言总能在常量空间中执行迭代 计算过程,即使这一计算是用一个递归过 程描述的——尾递归 • 更精妙的描述:递归调用返回的结果总被
直接返回