SlideShare a Scribd company logo
那些 Functional
                  Programming 教我的事
                       ihower@gmail.com
                           2012/4/15
                           OSDC.TW




Sunday, April 15, 12
About Me

                       • 張文鈿 a.k.a. ihower
                       • Twitter: @ihower
                       • Ruby 熟手、Scala 初心者
                       • Ruby on Rails 源碼貢獻者
                       • 熱情豆行動樂活科技

Sunday, April 15, 12
Agenda


                       • 1. 為什麼想學FP?
                       • 2. FP有什麼特色?


Sunday, April 15, 12
Part1:

                   為什麼想學 Functional
                     Programming


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




Sunday, April 15, 12
Single-Threading can’t
                               scale!




                                            4 Cores
Sunday, April 15, 12
Horizontal scaling
                       Q: 你的程式 Concurrency Ready 嗎?




Sunday, April 15, 12
Multithreading Program
                           Demo


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


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




Sunday, April 15, 12
Thread safe (2)


                       • 操作必須注意 Atomic



Sunday, April 15, 12
Thread safe (3)


                       • 要有個策略可以避免 Deadlock



Sunday, April 15, 12
Thread safe (4)


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




Sunday, April 15, 12
另⼀一個問題...


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




Sunday, April 15, 12
Multi-threading
                       Programing is Hard



Sunday, April 15, 12
Hard to program
                        只好讓團隊中最聰明的人去寫




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




Sunday, April 15, 12
會這麼難的根本原因:

                       Mutable shared state



Sunday, April 15, 12
如果有⼀一種程式語言



                       沒有 Mutable 變數




Sunday, April 15, 12
沒有 Mutable 變數,
                       那就不需要擔心 Synchronize
                            問題啦!!



Sunday, April 15, 12
Functional Programing
                           早在還沒有多核CPU的50年前




Sunday, April 15, 12
(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
(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
Functional Language
                           提供了開發
                       Concurrency program
                           的良好基礎

Sunday, April 15, 12
目前有哪些主流
                       Functional Language?


Sunday, April 15, 12
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
Erlang 業界案例
                       • Facebook chat
                       • Github
                       • RabbitMQ
                       • NoSQL
                        • CouchDB, Riak, Membase

Sunday, April 15, 12
Clojure

                  • Lisp-like functional language
                  • JVM
                  • Use STM   (Software transactional memory)   for concurrency
                   • 記憶體層級的 ACI                  (Atomicity, Consistent, Isolation)




Sunday, April 15, 12
• Hybrid: Object-orient and functional
                       • JVM
                       • Use Akka (Actor and STM) for concurrency


Sunday, April 15, 12
Scala 業界案例

                       • Twitter
                       • LinkedIn



Sunday, April 15, 12
F#

                       • Microsoft’s functional language
                       • .NET
                       • OCaml-like



Sunday, April 15, 12
Haskell


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

                       • 紀念數學家 Haskell Curry


Sunday, April 15, 12
小結

                       • 多核時代,需要能 Concurrency 的程式
                       • 用程序性的OO語言寫 Concurrency 很難
                       • Functional Programing 讓 Concurrency
                         Programming 變簡單




Sunday, April 15, 12
Part2:

                       FP 的幾個特色



Sunday, April 15, 12
• 1. Avoiding Mutable State
                       • 2. Recursion
                       • 3. Higher-Order Functions
                       • 4. Function Composition
                       • 5. Lazy Evaluation
                       • 6. Pattern Matching

Sunday, April 15, 12
1. 避免 Mutable State



Sunday, April 15, 12
在FP語言中,變數指
                   派之後就是 immutable
                       ** Erlang R15B **
                       X = 1234.

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




Sunday, April 15, 12
在 Scala 中,使用 val
                            宣告變數
              val a = 1234

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

              var b = 1234
              b = 5678
              5678


Sunday, April 15, 12
Persistent data
                             structure
                 • Immutable 的 Map, Hash, Set 等等
                 • 跟資料庫無關,而是因為其內部實作特性
                  • Produce new values by sharing structure
                       with existing values




Sunday, April 15, 12
Why need Immutable
                         data structure?

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


Sunday, April 15, 12
Linked List
                       相加兩個List,會共享已有的資料




Sunday, April 15, 12
Tree   (內部實作)

                       建立新的Tree時,共享資料




Sunday, April 15, 12
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
2. Recursion
                       遞迴只應天上有,凡人應當用迴圈?




Sunday, April 15, 12
Non-recursion
                               需要 result 變數

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

                         return result
                       end



Sunday, April 15, 12
Recursion
                         用 recursion 可以不需要中間變數



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




Sunday, April 15, 12
Recursion?
                             但是 call stack 爆炸了?




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




Sunday, April 15, 12
Tail-call optimization
                             FP程式語言會負責轉成 loop (例:Scala)




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




Sunday, April 15, 12
3. Higher-Order
                       function 的應用



Sunday, April 15, 12
Function is first-class
                            value      ( JavaScript 例)




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

                         sayHello();




Sunday, April 15, 12
Higher-order function


                       • 可以把 function 做參數傳遞到 function 裡
                       • function 可以當做 function 回傳的結果


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

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


Sunday, April 15, 12
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
JDK 8 開始支援
                              lambda
                       final Button button = new
                       Button(this);
                       button.setOnClickListener(
                          (View v) -> { "Hello" }
                       );




Sunday, April 15, 12
Combinator Functions

                       • 操作 Collection 的基本三招
                        • filter 去除某些元素,回傳新的容器
                        • map 轉變每個元素,回傳新的容器
                        • fold 迭代計算每個元素,回傳結果

Sunday, April 15, 12
範例:找出 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
傳統命令式流程
                       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 = 0
                       for(price <- prices) {
                         highestPrice = pickHighPriced(highestPrice,
                       price)
                       }

                       highestPrice

Sunday, April 15, 12
Functional Style

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




Sunday, April 15, 12
Functional Style
                                                              [1100, 900,800]
                       val highestPrice =
                              tickets.map{ x => getPrice(x) }
                                     .filter{ x => Less1000(x) }
                                     .reduce{ (x,y) => pickHighPriced(x,y) }




Sunday, April 15, 12
Functional Style

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




Sunday, April 15, 12
Functional Style

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




Sunday, April 15, 12
Scala 可以用 _ 簡化

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




Sunday, April 15, 12
繼續簡化

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




Sunday, April 15, 12
Scala 可以用空隔做
                            method call
          val higtestPrice =
             tickets map getPrice filter Less1000 reduce pickHighPriced




Sunday, April 15, 12
State transformation
                       不需要 Mutate 變數就可以處理 Collection




Sunday, April 15, 12
4. Function Composition
                       拆解和組合函式




Sunday, April 15, 12
Partial Functions
                       固定某些參數,回傳新的 Function




Sunday, April 15, 12
Haskell
                       add x y = x + y
                       add 2 3
                       # 5

                       addTwo = add 2
                       addTwo 3
                       # 5




Sunday, April 15, 12
Scala
                                   用⼀一個 _ wildcard


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

                       val addTwo = add(2, _:Int)

                       addTwo(3)
                       //5




Sunday, April 15, 12
Currying
                              named after Haskell Curry



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




Sunday, April 15, 12
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
Haskell
                           每個 function 都是 Curried,其實都只有⼀一個參數



                       max 4 5
                                       (max 4) 先得到⼀一個
                       # 其實是         Partial Function,然後再
                                               帶入5
                       (max 4) 5

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



Sunday, April 15, 12
Scala
                       可以將函式定義成 Curried 形式

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

                       def curriedSum(a: Int)(b: Int) = a * b
                       curriedSum(2)(3) // 5
                                                     curriedSum(2)
                                                  先得到⼀一個 Partial
                                                Function,然後再帶入3




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


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




Sunday, April 15, 12
Haskell
                         中間的串列省掉了
                       reverse( sort [2,5,1,10,5] )

                       # -- the '.' operator is used to
                       compose functions
                       reverseSort = reverse . sort
                       reverseSort [2,5,1,10,5]




Sunday, April 15, 12
JavaScript
                            也可以自定 compose 方法




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




Sunday, April 15, 12
5. Lazy evaluation

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


Sunday, April 15, 12
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
Scala’s lazy val
                                useful 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
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
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
6. Pattern Matching

                       • 模式比對
                        • 比對兩個 expression 是否可以相同
                       • 用途
                        • 控制結構
                        • 指派變數

Sunday, April 15, 12
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
Erlang
                          來試試 List



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

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




Sunday, April 15, 12
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
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
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
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
總結



Sunday, April 15, 12
Functional Style

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




Sunday, April 15, 12
要怎麼開始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
入門推薦書籍




Sunday, April 15, 12
Thanks.
                       • 感謝 @godfat (Haskell強者) 、大貓和
                        @idryman (Lisp 強者) 的指教

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




Sunday, April 15, 12

More Related Content

Similar to 那些 Functional Programming 教我的事 (20)

PDF
Scala
popeast
 
PDF
Enterprise javascriptsession1
Troy Miles
 
PDF
Cassandra Day 2014: Interactive Analytics with Cassandra and Spark
Evan Chan
 
PDF
Future Programming Languages
Alcides Fonseca
 
PDF
Ruby on Rails (RoR) as a back-end processor for Apex
Espen Brækken
 
PDF
Journey to 1000 tests a day
Bruce McLeod
 
PDF
static ABAP code analyzers
Markus Theilen
 
PDF
eZ Publish nextgen
Jérôme Vieilledent
 
PDF
Cloud Foundry the Open PaaS - OpenTour Austin Keynote
Patrick Chanezon
 
PDF
Software Libraries And Numbers
Robert Reiz
 
PPTX
Scala adoption by enterprises
Mike Slinn
 
KEY
Polyglot and functional (Devoxx Nov/2011)
Martijn Verburg
 
PDF
Pinterest arch summit august 2012 - scaling pinterest
drewz lin
 
PDF
LiveRebel + Pragmatic Continuous Delivery (Arcusys)
Neeme Praks
 
PDF
GitHub Notable OSS Project
roumia
 
PDF
Experience Converting from Ruby to Scala
John Nestor
 
PDF
Phingified ci and deployment strategies ipc 2012
TEQneers GmbH & Co. KG
 
PDF
Whitepages Practical Experience Converting from Ruby to Reactive
Dragos Manolescu
 
PDF
All Your IOPS Are Belong To Us - A Pinteresting Case Study in MySQL Performan...
Ernie Souhrada
 
PDF
Plumbr case study
Nikita Salnikov-Tarnovski
 
Scala
popeast
 
Enterprise javascriptsession1
Troy Miles
 
Cassandra Day 2014: Interactive Analytics with Cassandra and Spark
Evan Chan
 
Future Programming Languages
Alcides Fonseca
 
Ruby on Rails (RoR) as a back-end processor for Apex
Espen Brækken
 
Journey to 1000 tests a day
Bruce McLeod
 
static ABAP code analyzers
Markus Theilen
 
eZ Publish nextgen
Jérôme Vieilledent
 
Cloud Foundry the Open PaaS - OpenTour Austin Keynote
Patrick Chanezon
 
Software Libraries And Numbers
Robert Reiz
 
Scala adoption by enterprises
Mike Slinn
 
Polyglot and functional (Devoxx Nov/2011)
Martijn Verburg
 
Pinterest arch summit august 2012 - scaling pinterest
drewz lin
 
LiveRebel + Pragmatic Continuous Delivery (Arcusys)
Neeme Praks
 
GitHub Notable OSS Project
roumia
 
Experience Converting from Ruby to Scala
John Nestor
 
Phingified ci and deployment strategies ipc 2012
TEQneers GmbH & Co. KG
 
Whitepages Practical Experience Converting from Ruby to Reactive
Dragos Manolescu
 
All Your IOPS Are Belong To Us - A Pinteresting Case Study in MySQL Performan...
Ernie Souhrada
 
Plumbr case study
Nikita Salnikov-Tarnovski
 

More from Wen-Tien Chang (20)

PDF
評估驅動開發 Eval-Driven Development (EDD): 生成式 AI 軟體不確定性的解決方法
Wen-Tien Chang
 
PDF
⼤語⾔模型 LLM 應⽤開發入⾨
Wen-Tien Chang
 
PDF
Ruby Rails 老司機帶飛
Wen-Tien Chang
 
PDF
A brief introduction to Machine Learning
Wen-Tien Chang
 
PDF
RSpec on Rails Tutorial
Wen-Tien Chang
 
PDF
RSpec & TDD Tutorial
Wen-Tien Chang
 
PDF
ALPHAhackathon: How to collaborate
Wen-Tien Chang
 
PDF
Git 版本控制系統 -- 從微觀到宏觀
Wen-Tien Chang
 
PDF
Exception Handling: Designing Robust Software in Ruby (with presentation note)
Wen-Tien Chang
 
PDF
Exception Handling: Designing Robust Software in Ruby
Wen-Tien Chang
 
PDF
從 Classes 到 Objects: 那些 OOP 教我的事
Wen-Tien Chang
 
PDF
Yet another introduction to Git - from the bottom up
Wen-Tien Chang
 
PDF
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
Wen-Tien Chang
 
PDF
Ruby 程式語言綜覽簡介
Wen-Tien Chang
 
PDF
A brief introduction to SPDY - 邁向 HTTP/2.0
Wen-Tien Chang
 
PDF
RubyConf Taiwan 2012 Opening & Closing
Wen-Tien Chang
 
PDF
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
Wen-Tien Chang
 
PDF
Git Tutorial 教學
Wen-Tien Chang
 
PDF
RubyConf Taiwan 2011 Opening & Closing
Wen-Tien Chang
 
PDF
Git and Github
Wen-Tien Chang
 
評估驅動開發 Eval-Driven Development (EDD): 生成式 AI 軟體不確定性的解決方法
Wen-Tien Chang
 
⼤語⾔模型 LLM 應⽤開發入⾨
Wen-Tien Chang
 
Ruby Rails 老司機帶飛
Wen-Tien Chang
 
A brief introduction to Machine Learning
Wen-Tien Chang
 
RSpec on Rails Tutorial
Wen-Tien Chang
 
RSpec & TDD Tutorial
Wen-Tien Chang
 
ALPHAhackathon: How to collaborate
Wen-Tien Chang
 
Git 版本控制系統 -- 從微觀到宏觀
Wen-Tien Chang
 
Exception Handling: Designing Robust Software in Ruby (with presentation note)
Wen-Tien Chang
 
Exception Handling: Designing Robust Software in Ruby
Wen-Tien Chang
 
從 Classes 到 Objects: 那些 OOP 教我的事
Wen-Tien Chang
 
Yet another introduction to Git - from the bottom up
Wen-Tien Chang
 
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
Wen-Tien Chang
 
Ruby 程式語言綜覽簡介
Wen-Tien Chang
 
A brief introduction to SPDY - 邁向 HTTP/2.0
Wen-Tien Chang
 
RubyConf Taiwan 2012 Opening & Closing
Wen-Tien Chang
 
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
Wen-Tien Chang
 
Git Tutorial 教學
Wen-Tien Chang
 
RubyConf Taiwan 2011 Opening & Closing
Wen-Tien Chang
 
Git and Github
Wen-Tien Chang
 
Ad

那些 Functional Programming 教我的事

  • 1. 那些 Functional Programming 教我的事 [email protected] 2012/4/15 OSDC.TW Sunday, April 15, 12
  • 2. About Me • 張文鈿 a.k.a. ihower • Twitter: @ihower • Ruby 熟手、Scala 初心者 • Ruby on Rails 源碼貢獻者 • 熱情豆行動樂活科技 Sunday, April 15, 12
  • 3. Agenda • 1. 為什麼想學FP? • 2. FP有什麼特色? Sunday, April 15, 12
  • 4. Part1: 為什麼想學 Functional Programming Sunday, April 15, 12
  • 5. Moore’s Law Ending 單核時脈無法再提昇了,多核架構是現在進行式 Sunday, April 15, 12
  • 6. Single-Threading can’t scale! 4 Cores Sunday, April 15, 12
  • 7. Horizontal scaling Q: 你的程式 Concurrency Ready 嗎? Sunday, April 15, 12
  • 8. Multithreading Program Demo Example from: What All Rubyist Should Know About Threads (Jim Weirich, RubyConf 2008) Sunday, April 15, 12
  • 9. Thread-safe (1) • 每個存取到的共享變數,都要 Synchronize Sunday, April 15, 12
  • 10. Thread safe (2) • 操作必須注意 Atomic Sunday, April 15, 12
  • 11. Thread safe (3) • 要有個策略可以避免 Deadlock Sunday, April 15, 12
  • 12. Thread safe (4) • 每個你用到的 Library 都必須滿足上述規 則 (1)~(3) Sunday, April 15, 12
  • 13. 另⼀一個問題... • Synchronized 太多了,都是 blocking threads,程式同時間只有⼀一個 thread 在 跑 :( Sunday, April 15, 12
  • 14. Multi-threading Programing is Hard Sunday, April 15, 12
  • 15. Hard to program 只好讓團隊中最聰明的人去寫 Sunday, April 15, 12
  • 16. Hard to test 測試無法窮舉各種情況,上線後不定時爆炸 Sunday, April 15, 12
  • 17. 會這麼難的根本原因: Mutable shared state Sunday, April 15, 12
  • 18. 如果有⼀一種程式語言 沒有 Mutable 變數 Sunday, April 15, 12
  • 19. 沒有 Mutable 變數, 那就不需要擔心 Synchronize 問題啦!! Sunday, April 15, 12
  • 20. Functional Programing 早在還沒有多核CPU的50年前 Sunday, April 15, 12
  • 21. (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
  • 22. (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
  • 23. Functional Language 提供了開發 Concurrency program 的良好基礎 Sunday, April 15, 12
  • 24. 目前有哪些主流 Functional Language? Sunday, April 15, 12
  • 25. 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
  • 26. Erlang 業界案例 • Facebook chat • Github • RabbitMQ • NoSQL • CouchDB, Riak, Membase Sunday, April 15, 12
  • 27. Clojure • Lisp-like functional language • JVM • Use STM (Software transactional memory) for concurrency • 記憶體層級的 ACI (Atomicity, Consistent, Isolation) Sunday, April 15, 12
  • 28. • Hybrid: Object-orient and functional • JVM • Use Akka (Actor and STM) for concurrency Sunday, April 15, 12
  • 29. Scala 業界案例 • Twitter • LinkedIn Sunday, April 15, 12
  • 30. F# • Microsoft’s functional language • .NET • OCaml-like Sunday, April 15, 12
  • 31. Haskell • Pure Functional language 研究領域上的統⼀一 標準實作 • 紀念數學家 Haskell Curry Sunday, April 15, 12
  • 32. 小結 • 多核時代,需要能 Concurrency 的程式 • 用程序性的OO語言寫 Concurrency 很難 • Functional Programing 讓 Concurrency Programming 變簡單 Sunday, April 15, 12
  • 33. Part2: FP 的幾個特色 Sunday, April 15, 12
  • 34. • 1. Avoiding Mutable State • 2. Recursion • 3. Higher-Order Functions • 4. Function Composition • 5. Lazy Evaluation • 6. Pattern Matching Sunday, April 15, 12
  • 35. 1. 避免 Mutable State Sunday, April 15, 12
  • 36. 在FP語言中,變數指 派之後就是 immutable ** Erlang R15B ** X = 1234. X = 5678. ** exception error: no match of right hand side value 5678 Sunday, April 15, 12
  • 37. 在 Scala 中,使用 val 宣告變數 val a = 1234 a = 5678 <console>:8: error: reassignment to val var b = 1234 b = 5678 5678 Sunday, April 15, 12
  • 38. Persistent data structure • Immutable 的 Map, Hash, Set 等等 • 跟資料庫無關,而是因為其內部實作特性 • Produce new values by sharing structure with existing values Sunday, April 15, 12
  • 39. Why need Immutable data structure? • No side-effects 的效能衝擊!! • Copying overhead Sunday, April 15, 12
  • 40. Linked List 相加兩個List,會共享已有的資料 Sunday, April 15, 12
  • 41. Tree (內部實作) 建立新的Tree時,共享資料 Sunday, April 15, 12
  • 42. 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
  • 43. 2. Recursion 遞迴只應天上有,凡人應當用迴圈? Sunday, April 15, 12
  • 44. Non-recursion 需要 result 變數 def factorial(n) result = 1 # result 是變數 for i in 2..n result = i * result end return result end Sunday, April 15, 12
  • 45. Recursion 用 recursion 可以不需要中間變數 def factorial(n) if (n==1) return 1 else return n * factorial(n-1) end end Sunday, April 15, 12
  • 46. Recursion? 但是 call stack 爆炸了? > factorial(10000) # SystemStackError: stack level too deep Sunday, April 15, 12
  • 47. Tail-call optimization FP程式語言會負責轉成 loop (例:Scala) @tailrec def factorial(acc: Int, n: Int): Int = { if (n <= 1) acc else factorial(n * acc, n - 1) } Sunday, April 15, 12
  • 48. 3. Higher-Order function 的應用 Sunday, April 15, 12
  • 49. Function is first-class value ( JavaScript 例) var sayHello = function(){ alert("Hello World!"); }; sayHello(); Sunday, April 15, 12
  • 50. Higher-order function • 可以把 function 做參數傳遞到 function 裡 • function 可以當做 function 回傳的結果 Sunday, April 15, 12
  • 51. JavaScript (ECMA5) forEach [2,3,5,6].forEach( function(item){ console.log(item); } ); // 2 // 3 // 5 // 6 Sunday, April 15, 12
  • 52. 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
  • 53. JDK 8 開始支援 lambda final Button button = new Button(this); button.setOnClickListener( (View v) -> { "Hello" } ); Sunday, April 15, 12
  • 54. Combinator Functions • 操作 Collection 的基本三招 • filter 去除某些元素,回傳新的容器 • map 轉變每個元素,回傳新的容器 • fold 迭代計算每個元素,回傳結果 Sunday, April 15, 12
  • 55. 範例:找出 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
  • 56. 傳統命令式流程 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 = 0 for(price <- prices) { highestPrice = pickHighPriced(highestPrice, price) } highestPrice Sunday, April 15, 12
  • 57. Functional Style val highestPrice = tickets.map{ x => getPrice(x) } .filter{ x => Less1000(x) } [“a”, “b”,”c”] .reduce{ (x,y) => pickHighPriced(x,y) } Sunday, April 15, 12
  • 58. Functional Style [1100, 900,800] val highestPrice = tickets.map{ x => getPrice(x) } .filter{ x => Less1000(x) } .reduce{ (x,y) => pickHighPriced(x,y) } Sunday, April 15, 12
  • 59. Functional Style val highestPrice = [900,800] tickets.map{ x => getPrice(x) } .filter{ x => Less1000(x) } .reduce{ (x,y) => pickHighPriced(x,y) } Sunday, April 15, 12
  • 60. Functional Style val highestPrice = tickets.map{ x => getPrice(x) } 900 .filter{ x => Less1000(x) } .reduce{ (x,y) => pickHighPriced(x,y) } Sunday, April 15, 12
  • 61. Scala 可以用 _ 簡化 val highestPrice = tickets.map{ getPrice(_) } .filter{ Less1000(_) } .reduce{ pickHighPriced(_,_) } Sunday, April 15, 12
  • 62. 繼續簡化 val higtestPrice = tickets.map.getPrice.filter.Less1000.reduce.pickHighPriced Sunday, April 15, 12
  • 63. Scala 可以用空隔做 method call val higtestPrice = tickets map getPrice filter Less1000 reduce pickHighPriced Sunday, April 15, 12
  • 64. State transformation 不需要 Mutate 變數就可以處理 Collection Sunday, April 15, 12
  • 65. 4. Function Composition 拆解和組合函式 Sunday, April 15, 12
  • 66. Partial Functions 固定某些參數,回傳新的 Function Sunday, April 15, 12
  • 67. Haskell add x y = x + y add 2 3 # 5 addTwo = add 2 addTwo 3 # 5 Sunday, April 15, 12
  • 68. Scala 用⼀一個 _ wildcard def add(x:Int, y:Int) = x + y val addTwo = add(2, _:Int) addTwo(3) //5 Sunday, April 15, 12
  • 69. Currying named after Haskell Curry • 將⼀一個有 N 個參數的 function 轉換成 N 個只有⼀一個參數的 function 的過程 Sunday, April 15, 12
  • 70. 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
  • 71. Haskell 每個 function 都是 Curried,其實都只有⼀一個參數 max 4 5 (max 4) 先得到⼀一個 # 其實是 Partial Function,然後再 帶入5 (max 4) 5 # max函式的宣告是 max :: Ord a => a -> (a -> a) max 4 :: (Ord a, Num a) => a -> a Sunday, April 15, 12
  • 72. Scala 可以將函式定義成 Curried 形式 def sum(a: Int, b: Int) = a + b sum(2, 3) // 5 def curriedSum(a: Int)(b: Int) = a * b curriedSum(2)(3) // 5 curriedSum(2) 先得到⼀一個 Partial Function,然後再帶入3 Sunday, April 15, 12
  • 73. Compose 把兩個⼀一個參數的 Function 合併起來 可以串聯多個組合成新的函數 f(g(x)) = (f。g)(x) Sunday, April 15, 12
  • 74. Haskell 中間的串列省掉了 reverse( sort [2,5,1,10,5] ) # -- the '.' operator is used to compose functions reverseSort = reverse . sort reverseSort [2,5,1,10,5] Sunday, April 15, 12
  • 75. JavaScript 也可以自定 compose 方法 function compose(f, g) { return function(x) { return f(g(x)); } } Sunday, April 15, 12
  • 76. 5. Lazy evaluation • 直到真的需要才執行 • 增加效率,減少沒有用到的計算 • 可以簡潔地表達無窮 list Sunday, April 15, 12
  • 77. 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
  • 78. Scala’s lazy val useful 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
  • 79. 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
  • 80. 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
  • 81. 6. Pattern Matching • 模式比對 • 比對兩個 expression 是否可以相同 • 用途 • 控制結構 • 指派變數 Sunday, April 15, 12
  • 82. 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
  • 83. Erlang 來試試 List [H|T] = [1,2,3,4,5]. H. "1" T. "[2,3,4,5]" Sunday, April 15, 12
  • 84. 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
  • 85. 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
  • 86. 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
  • 87. 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
  • 89. Functional Style • 強調 immutability,避免 Function 的 Side-effects • 雖然還是無法完全避免 side-effects (例如IO), 但是 FP Style 降低了 Mutable State,增加程式 碼正確性和 Concurrency 能力。 Sunday, April 15, 12
  • 90. 要怎麼開始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
  • 92. Thanks. • 感謝 @godfat (Haskell強者) 、大貓和 @idryman (Lisp 強者) 的指教 • 如果你有在寫FP,歡迎來找我聊聊、交 換名片,也許有機會來辦⼀一個 FP user group 聚會 :-) Sunday, April 15, 12