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
「リーダーは意思決定する人」って本当?~ 学びを現場で活かす、リーダー4ヶ月目の試行錯誤 ~
marina1017
0
210
一人でAIプロダクトを作るための工夫 〜技術選定・開発プロセス編〜 / I want AI to work harder
rkaga
11
2.5k
Infer入門
riru
4
1.4k
QA x AIエコシステム段階構築作戦
osu
0
260
Constant integer division faster than compiler-generated code
herumi
2
580
Vibe coding コードレビュー
kinopeee
0
430
Scale out your Claude Code ~自社専用Agentで10xする開発プロセス~
yukukotani
9
1.9k
decksh - a little language for decks
ajstarks
4
21k
Android 15以上でPDFのテキスト検索を爆速開発!
tonionagauzzi
0
200
管你要 trace 什麼、bpftrace 用下去就對了 — COSCUP 2025
shunghsiyu
0
380
DynamoDBは怖くない!〜テーブル設計の勘所とテスト戦略〜
hyamazaki
0
200
202507_ADKで始めるエージェント開発の基本 〜デモを通じて紹介〜(奥田りさ)The Basics of Agent Development with ADK — A Demo-Focused Introduction
risatube
PRO
6
1.4k
Featured
See All Featured
Scaling GitHub
holman
461
140k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Typedesign – Prime Four
hannesfritz
42
2.7k
Reflections from 52 weeks, 52 projects
jeffersonlam
351
21k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
36
2.5k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
229
22k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
6k
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.6k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.4k
Faster Mobile Websites
deanohume
308
31k
Balancing Empowerment & Direction
lara
1
540
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等语言总能在常量空间中执行迭代 计算过程,即使这一计算是用一个递归过 程描述的——尾递归 • 更精妙的描述:递归调用返回的结果总被
直接返回