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
190
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Functional Programming
runninghack
November 05, 2012
More Decks by runninghack
See All by runninghack
Object Orientation Is a Hoax
runninghack
1
200
Other Decks in Programming
See All in Programming
【やさしく解説 設計編 #1】「ドメイン駆動」と「実装駆動」ってなに? 〜設計の考え方を、たとえ話で学ぼう〜
panda728
PRO
1
120
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
850
AWS CDK を「作」ってみた 〜フルスクラッチで見えた CDK の裏側〜 / aws-cdk-from-scratch
gotok365
3
400
ビデオ通話が繋がる0.2秒で何が起きているのか
supurazako
2
150
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
150
アルゴリズムは何を圧縮しているのか ─ Haskell から育った「圧縮代数」というメンタルモデル
naoya
16
3.5k
【やさしく解説 設計編・中級 #6】良いアーキテクチャとは ~ 一本の登り道の、行き先 ~
panda728
PRO
0
160
【やさしく解説 設計編・中級 #1】一つの車に、運転手は一人 ~ある倉庫システムの事例から~
panda728
PRO
0
180
言語を使う側から、作る側へ。 自作 Lisp で得た新たな気づき。
andpad
0
120
Haskell/Servantを通してWebミドルウェアを捉え直す
pizzacat83
1
580
ランチタイムLT会3周年!ランチタイムLT会を3年間続けられたお話
y0hgi
1
140
PHPだって関数型したい 〜できること、できないこと〜 / fp-in-php
jsoizo
0
210
Featured
See All Featured
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.6k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
390
Utilizing Notion as your number one productivity tool
mfonobong
4
420
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
Heart Work Chapter 1 - Part 1
lfama
PRO
8
36k
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
220
Agile that works and the tools we love
rasmusluckow
331
22k
KATA
mclloyd
PRO
35
15k
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
2k
30 Presentation Tips
portentint
PRO
1
350
A designer walks into a library…
pauljervisheath
211
24k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
350
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等语言总能在常量空间中执行迭代 计算过程,即使这一计算是用一个递归过 程描述的——尾递归 • 更精妙的描述:递归调用返回的结果总被
直接返回