那些 functional programming 教我的事

92
那些 Functional Programming 教我的事 [email protected] 2012/4/15 OSDC.TW Sunday, April 15, 12

Post on 12-Sep-2014

16.798 views

Category:

Documents


0 download

DESCRIPTION

OSDC.TW 2012

TRANSCRIPT

Page 1: 那些 Functional Programming 教我的事

那些 Functional Programming 教我的事

[email protected]/4/15

OSDC.TW

Sunday, April 15, 12

Page 2: 那些 Functional Programming 教我的事

About Me

• 張文鈿 a.k.a. ihower

• Twitter: @ihower

• Ruby 熟手、Scala 初心者

• Ruby on Rails 源碼貢獻者

• 熱情豆行動樂活科技

Sunday, April 15, 12

Page 3: 那些 Functional Programming 教我的事

Agenda

• 1. 為什麼想學FP?

• 2. FP有什麼特色?

Sunday, April 15, 12

Page 4: 那些 Functional Programming 教我的事

Part1:

為什麼想學 Functional Programming

Sunday, April 15, 12

Page 5: 那些 Functional Programming 教我的事

Moore’s Law Ending單核時脈無法再提昇了,多核架構是現在進行式

Sunday, April 15, 12

Page 6: 那些 Functional Programming 教我的事

Single-Threading can’t scale!

4 Cores

Sunday, April 15, 12

Page 7: 那些 Functional Programming 教我的事

Horizontal scalingQ: 你的程式 Concurrency Ready 嗎?

Sunday, April 15, 12

Page 8: 那些 Functional Programming 教我的事

Multithreading ProgramDemo

Example from: What All Rubyist Should Know About Threads (Jim Weirich, RubyConf 2008)Sunday, April 15, 12

Page 9: 那些 Functional Programming 教我的事

Thread-safe (1)

• 每個存取到的共享變數,都要 Synchronize

Sunday, April 15, 12

Page 10: 那些 Functional Programming 教我的事

Thread safe (2)

• 操作必須注意 Atomic

Sunday, April 15, 12

Page 11: 那些 Functional Programming 教我的事

Thread safe (3)

• 要有個策略可以避免 Deadlock

Sunday, April 15, 12

Page 12: 那些 Functional Programming 教我的事

Thread safe (4)

• 每個你用到的 Library 都必須滿足上述規則 (1)~(3)

Sunday, April 15, 12

Page 13: 那些 Functional Programming 教我的事

另⼀一個問題...

• Synchronized 太多了,都是 blocking threads,程式同時間只有⼀一個 thread 在跑 :(

Sunday, April 15, 12

Page 14: 那些 Functional Programming 教我的事

Multi-threading Programing is Hard

Sunday, April 15, 12

Page 15: 那些 Functional Programming 教我的事

Hard to program只好讓團隊中最聰明的人去寫

Sunday, April 15, 12

Page 16: 那些 Functional Programming 教我的事

Hard to test測試無法窮舉各種情況,上線後不定時爆炸

Sunday, April 15, 12

Page 17: 那些 Functional Programming 教我的事

會這麼難的根本原因:

Mutable shared state

Sunday, April 15, 12

Page 18: 那些 Functional Programming 教我的事

如果有⼀一種程式語言

沒有 Mutable 變數

Sunday, April 15, 12

Page 19: 那些 Functional Programming 教我的事

沒有 Mutable 變數,那就不需要擔心 Synchronize

問題啦!!

Sunday, April 15, 12

Page 20: 那些 Functional Programming 教我的事

Functional Programing早在還沒有多核CPU的50年前

Sunday, April 15, 12

Page 21: 那些 Functional Programming 教我的事

(Wikipedia)In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast to the imperative programming style, which emphasizes changes in state.

Sunday, April 15, 12

Page 22: 那些 Functional Programming 教我的事

(Wikipedia)In computer science, functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids state and mutable data. It emphasizes the application of functions, in contrast to the imperative programming style, which emphasizes changes in state.

Sunday, April 15, 12

Page 23: 那些 Functional Programming 教我的事

Functional Language 提供了開發

Concurrency program的良好基礎

Sunday, April 15, 12

Page 24: 那些 Functional Programming 教我的事

目前有哪些主流 Functional Language?

Sunday, April 15, 12

Page 25: 那些 Functional Programming 教我的事

Erlang

• Ericsson Functional Language

• No mutable variable and side effects

• For distributed, reliable, soft real-time highly concurrent systems.

• Use the Actor model of concurrency

Sunday, April 15, 12

Page 26: 那些 Functional Programming 教我的事

Erlang 業界案例• Facebook chat

• Github

• RabbitMQ

• NoSQL

• CouchDB, Riak, Membase

Sunday, April 15, 12

Page 27: 那些 Functional Programming 教我的事

Clojure

• Lisp-like functional language

• JVM

• Use STM (Software transactional memory) for concurrency

• 記憶體層級的 ACI (Atomicity, Consistent, Isolation)

Sunday, April 15, 12

Page 28: 那些 Functional Programming 教我的事

• Hybrid: Object-orient and functional

• JVM

• Use Akka (Actor and STM) for concurrency

Sunday, April 15, 12

Page 29: 那些 Functional Programming 教我的事

• Twitter

• LinkedIn

Scala 業界案例

Sunday, April 15, 12

Page 30: 那些 Functional Programming 教我的事

F#

• Microsoft’s functional language

• .NET

• OCaml-like

Sunday, April 15, 12

Page 31: 那些 Functional Programming 教我的事

Haskell

• Pure Functional language 研究領域上的統⼀一標準實作

• 紀念數學家 Haskell Curry

Sunday, April 15, 12

Page 32: 那些 Functional Programming 教我的事

小結

• 多核時代,需要能 Concurrency 的程式

• 用程序性的OO語言寫 Concurrency 很難

• Functional Programing 讓 Concurrency Programming 變簡單

Sunday, April 15, 12

Page 33: 那些 Functional Programming 教我的事

Part2:

FP 的幾個特色

Sunday, April 15, 12

Page 34: 那些 Functional Programming 教我的事

• 1. Avoiding Mutable State

• 2. Recursion

• 3. Higher-Order Functions

• 4. Function Composition

• 5. Lazy Evaluation

• 6. Pattern Matching

Sunday, April 15, 12

Page 35: 那些 Functional Programming 教我的事

1. 避免 Mutable State

Sunday, April 15, 12

Page 36: 那些 Functional Programming 教我的事

在FP語言中,變數指派之後就是 immutable

** Erlang R15B **X = 1234.

X = 5678.** exception error: no match of right hand side value 5678

Sunday, April 15, 12

Page 37: 那些 Functional Programming 教我的事

在 Scala 中,使用 val 宣告變數

val a = 1234

a = 5678<console>:8: error: reassignment to val

var b = 1234b = 56785678

Sunday, April 15, 12

Page 38: 那些 Functional Programming 教我的事

Persistent data structure

• Immutable 的 Map, Hash, Set 等等

• 跟資料庫無關,而是因為其內部實作特性• Produce new values by sharing structure

with existing values

Sunday, April 15, 12

Page 39: 那些 Functional Programming 教我的事

Why need Immutable data structure?

• No side-effects 的效能衝擊!!

• Copying overhead

Sunday, April 15, 12

Page 40: 那些 Functional Programming 教我的事

Linked List相加兩個List,會共享已有的資料

Sunday, April 15, 12

Page 41: 那些 Functional Programming 教我的事

Tree (內部實作)

建立新的Tree時,共享資料

Sunday, April 15, 12

Page 42: 那些 Functional Programming 教我的事

Scala’s collection• 預設提供 Immutable 資料結構

• List

• Map

• Vector

• Set

• Mutable 的資料結構需要額外 import

• scala.collection.mutable.LinkedList

• scala.collection.mutable.Map

• scala.collection.mutable.ArrayBuffer

• scala.collection.mutable.Set

Sunday, April 15, 12

Page 43: 那些 Functional Programming 教我的事

2. Recursion遞迴只應天上有,凡人應當用迴圈?

Sunday, April 15, 12

Page 44: 那些 Functional Programming 教我的事

Non-recursion需要 result 變數

def factorial(n) result = 1 # result 是變數 for i in 2..n result = i * result end return resultend

Sunday, April 15, 12

Page 45: 那些 Functional Programming 教我的事

Recursion用 recursion 可以不需要中間變數

def factorial(n) if (n==1) return 1 else return n * factorial(n-1) endend

Sunday, April 15, 12

Page 46: 那些 Functional Programming 教我的事

Recursion?但是 call stack 爆炸了?

> factorial(10000)# SystemStackError: stack level too deep

Sunday, April 15, 12

Page 47: 那些 Functional Programming 教我的事

Tail-call optimizationFP程式語言會負責轉成 loop (例:Scala)

@tailrec def factorial(acc: Int, n: Int): Int = { if (n <= 1) acc else factorial(n * acc, n - 1)}

Sunday, April 15, 12

Page 48: 那些 Functional Programming 教我的事

3. Higher-Order function 的應用

Sunday, April 15, 12

Page 49: 那些 Functional Programming 教我的事

Function is first-class value ( JavaScript 例)

var sayHello = function(){ alert("Hello World!");};

sayHello();

Sunday, April 15, 12

Page 50: 那些 Functional Programming 教我的事

Higher-order function

• 可以把 function 做參數傳遞到 function 裡

• function 可以當做 function 回傳的結果

Sunday, April 15, 12

Page 51: 那些 Functional Programming 教我的事

JavaScript (ECMA5) forEach [2,3,5,6].forEach( function(item){ console.log(item); });

// 2// 3// 5// 6

Sunday, April 15, 12

Page 52: 那些 Functional Programming 教我的事

Callback method( Java 需要用 Anonymous inner class)

final Button button = new Button(this);button.setOnClickListener(

);

new View.OnClickListener() { public void onClick(View v) { "Hello, World!"}}

Sunday, April 15, 12

Page 53: 那些 Functional Programming 教我的事

JDK 8 開始支援 lambda

final Button button = new Button(this);button.setOnClickListener( );

(View v) -> { "Hello" }

Sunday, April 15, 12

Page 54: 那些 Functional Programming 教我的事

Combinator Functions

• 操作 Collection 的基本三招

• filter 去除某些元素,回傳新的容器

• map 轉變每個元素,回傳新的容器

• fold 迭代計算每個元素,回傳結果

Sunday, April 15, 12

Page 55: 那些 Functional Programming 教我的事

範例:找出 Tickets 價格小於1000中,最高的價格

val tickets = List("a","b", "c")

def getPrice(ticket : String) = { Map( "a" -> 1100, "b" -> 900, "c" -> 800 ). get(ticket).getOrElse(0)}

def Less1000(price: Int) = price < 1000

def pickHighPriced(price1: Int, price2: Int) = { if (price1 > price2) price1 else price2}

Sunday, April 15, 12

Page 56: 那些 Functional Programming 教我的事

傳統命令式流程import scala.collection.mutable.ArrayBuffer//抓出所有價格val prices = new ArrayBuffer[Int]for(ticket <- tickets) { prices += getPrice(ticket)}//去除大於1000的for(price <- prices){ if (!Less1000(price)) prices -= price}//跑迴圈找出最大值var highestPrice = 0for(price <- prices) { highestPrice = pickHighPriced(highestPrice, price)}

highestPrice

Sunday, April 15, 12

Page 57: 那些 Functional Programming 教我的事

Functional Style

val highestPrice = tickets.map{ x => getPrice(x) } .filter{ x => Less1000(x) } .reduce{ (x,y) => pickHighPriced(x,y) }[“a”, “b”,”c”]

Sunday, April 15, 12

Page 58: 那些 Functional Programming 教我的事

Functional Style

val highestPrice = tickets.map{ x => getPrice(x) } .filter{ x => Less1000(x) } .reduce{ (x,y) => pickHighPriced(x,y) }

[1100, 900,800]

Sunday, April 15, 12

Page 59: 那些 Functional Programming 教我的事

Functional Style

val highestPrice = tickets.map{ x => getPrice(x) } .filter{ x => Less1000(x) } .reduce{ (x,y) => pickHighPriced(x,y) }

[900,800]

Sunday, April 15, 12

Page 60: 那些 Functional Programming 教我的事

Functional Style

val highestPrice = tickets.map{ x => getPrice(x) } .filter{ x => Less1000(x) } .reduce{ (x,y) => pickHighPriced(x,y) }

900

Sunday, April 15, 12

Page 61: 那些 Functional Programming 教我的事

Scala 可以用 _ 簡化

val highestPrice = tickets.map{ getPrice(_) } .filter{ Less1000(_) } .reduce{ pickHighPriced(_,_) }

Sunday, April 15, 12

Page 62: 那些 Functional Programming 教我的事

繼續簡化

val higtestPrice = tickets.map.getPrice.filter.Less1000.reduce.pickHighPriced

Sunday, April 15, 12

Page 63: 那些 Functional Programming 教我的事

Scala 可以用空隔做 method call

val higtestPrice = tickets map getPrice filter Less1000 reduce pickHighPriced

Sunday, April 15, 12

Page 64: 那些 Functional Programming 教我的事

State transformation不需要 Mutate 變數就可以處理 Collection

Sunday, April 15, 12

Page 65: 那些 Functional Programming 教我的事

4. Function Composition拆解和組合函式

Sunday, April 15, 12

Page 66: 那些 Functional Programming 教我的事

Partial Functions固定某些參數,回傳新的 Function

Sunday, April 15, 12

Page 67: 那些 Functional Programming 教我的事

Haskelladd x y = x + yadd 2 3# 5

addTwo = add 2addTwo 3# 5

Sunday, April 15, 12

Page 68: 那些 Functional Programming 教我的事

Scala用⼀一個 _ wildcard

def add(x:Int, y:Int) = x + y

val addTwo = add(2, _:Int)

addTwo(3)//5

Sunday, April 15, 12

Page 69: 那些 Functional Programming 教我的事

Curryingnamed after Haskell Curry

• 將⼀一個有 N 個參數的 function 轉換成 N 個只有⼀一個參數的 function 的過程

Sunday, April 15, 12

Page 70: 那些 Functional Programming 教我的事

Haskell每個 function 都是 Curried,其實都只有⼀一個參數

max 4 5

# 其實是(max 4) 5

# max函式的宣告是max :: Ord a => a -> (a -> a)max 4 :: (Ord a, Num a) => a -> a

Sunday, April 15, 12

Page 71: 那些 Functional Programming 教我的事

Haskell每個 function 都是 Curried,其實都只有⼀一個參數

max 4 5

# 其實是(max 4) 5

# max函式的宣告是max :: Ord a => a -> (a -> a)max 4 :: (Ord a, Num a) => a -> a

(max 4) 先得到⼀一個 Partial Function,然後再

帶入5

Sunday, April 15, 12

Page 72: 那些 Functional Programming 教我的事

Scala可以將函式定義成 Curried 形式

def sum(a: Int, b: Int) = a + bsum(2, 3) // 5

def curriedSum(a: Int)(b: Int) = a * bcurriedSum(2)(3) // 5

curriedSum(2) 先得到⼀一個 Partial

Function,然後再帶入3

Sunday, April 15, 12

Page 73: 那些 Functional Programming 教我的事

Compose把兩個⼀一個參數的 Function 合併起來可以串聯多個組合成新的函數

f(g(x)) = (f。g)(x)

Sunday, April 15, 12

Page 74: 那些 Functional Programming 教我的事

Haskell中間的串列省掉了

reverse( sort [2,5,1,10,5] )

# -- the '.' operator is used to compose functionsreverseSort = reverse . sortreverseSort [2,5,1,10,5]

Sunday, April 15, 12

Page 75: 那些 Functional Programming 教我的事

JavaScript也可以自定 compose 方法

function compose(f, g) { return function(x) { return f(g(x)); }}

Sunday, April 15, 12

Page 76: 那些 Functional Programming 教我的事

5. Lazy evaluation

• 直到真的需要才執行• 增加效率,減少沒有用到的計算• 可以簡潔地表達無窮 list

Sunday, April 15, 12

Page 77: 那些 Functional Programming 教我的事

Haskell is lazy functional language

cycle [1,2,3]# [1,2,3, 1,2,3, 1,2,3, 1,2,3, 1,2,3, 1,2,3, 1,2,3,....

take 10 (cycle [1,2,3])# [1,2,3,1,2,3,1,2,3,1]"

Sunday, April 15, 12

Page 78: 那些 Functional Programming 教我的事

Scala’s lazy valuseful for lazy initialization

val a = { println("evaluating A"); "A" }// evaluating A// a: java.lang.String = A

lazy val b = { println("evaluating B"); "B" }// b: java.lang.String = <lazy>

Sunday, April 15, 12

Page 79: 那些 Functional Programming 教我的事

Scala Stream (lazy list)Scala 預設的 List 不是 Lazy

def from(n: Int): Stream[Int] = Stream.cons( n, from(n+1) )lazy val odds = from(0).filter(_ % 2 == 1)

odds.take(10).print // 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, empty

Sunday, April 15, 12

Page 80: 那些 Functional Programming 教我的事

Ruby Enumerable::Lazy 容器不是 Lazy 的話,無窮元素就不能套 Combinator

functions 了

require 'prime'

Prime.to_a # 這樣是無窮數列...

Prime.take(10).to_a# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Prime.lazy.select{ |x| x % 4 == 3 }.take(10).to_a# => [3, 7, 11, 19, 23, 31, 43, 47, 59, 67]

Sunday, April 15, 12

Page 81: 那些 Functional Programming 教我的事

6. Pattern Matching

• 模式比對• 比對兩個 expression 是否可以相同

• 用途• 控制結構• 指派變數

Sunday, April 15, 12

Page 82: 那些 Functional Programming 教我的事

Erlang用來比對然後指派變數

X."1: variable 'X' is unbound"

X = 2.

{X, Y} = {1, 2}."exception error: no match of right hand side value {1,2}"

{X, Y} = {2, 3}.{2,3}

Y."此時 Y 是 3"

Sunday, April 15, 12

Page 83: 那些 Functional Programming 教我的事

Erlang來試試 List

[H|T] = [1,2,3,4,5].

H. "1"T. "[2,3,4,5]"

Sunday, April 15, 12

Page 84: 那些 Functional Programming 教我的事

Erlang (cont.)來試試 List

[A,B,C|T] = [1,2,3,4,5].A. "1"B. "2"C. "3"T. "[4,5]"

Sunday, April 15, 12

Page 85: 那些 Functional Programming 教我的事

Scala用 match 比對

import scala.util.Random

val randomInt = new Random().nextInt(10)

randomInt match { case 7 => println("lucky seven") case otherNumber => println("get " + otherNumber)}

Sunday, April 15, 12

Page 86: 那些 Functional Programming 教我的事

Scala可以比對 Type

val items = List(1, "foo", 3.5)

for (item <- items) { item match { case i: Int => println("got an Integer: " + i) case s: String => println("got a String: " + s) case f: Double => println("got a Double: " + f) case other => println("got others: " + other) }}

Sunday, April 15, 12

Page 87: 那些 Functional Programming 教我的事

Scala可以加上 Guard 條件

val t1 = ("A", "B")val t2 = ("C", "D")val t3 = ("E", "F")

for( tuple <- List(t1, t2, t3) ) { tuple match { case (one, two) if one == "C" => println("得到開頭是C的tuple") case (one, two) => println("blah") }}

// blah// Got tuple starting with C// blah

Sunday, April 15, 12

Page 88: 那些 Functional Programming 教我的事

總結

Sunday, April 15, 12

Page 89: 那些 Functional Programming 教我的事

Functional Style

• 強調 immutability,避免 Function 的 Side-effects

• 雖然還是無法完全避免 side-effects (例如IO),但是 FP Style 降低了 Mutable State,增加程式碼正確性和 Concurrency 能力。

Sunday, April 15, 12

Page 90: 那些 Functional Programming 教我的事

要怎麼開始FP?• Functional Programing 不同程度地混搭在各種程式語言之中:

• Java 也可以寫 FP Style

• Scripting 語言(Ruby/Python/JavaScript) 也提供了很多 好用的 FP 技巧

• 但要學到 Avoid Mutable State 和 No-side Effects Function 的精髓,還是得試試 Functional 程式語言

• 建議多看看不同的 FP 語言,Lisp, Haskell, Scala, F# 概念相通但語法差蠻多的

Sunday, April 15, 12

Page 91: 那些 Functional Programming 教我的事

入門推薦書籍

Sunday, April 15, 12

Page 92: 那些 Functional Programming 教我的事

Thanks.

• 感謝 @godfat (Haskell強者) 、大貓和 @idryman (Lisp 強者) 的指教

• 如果你有在寫FP,歡迎來找我聊聊、交換名片,也許有機會來辦⼀一個 FP user group 聚會 :-)

Sunday, April 15, 12