Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Functional Way

231 views

Published on

フィボナッチ数の計算を例に関数型プログラミングの基本的な概念を紹介。
関数型プログラミングを始めよう!

Published in: Software
  • Be the first to comment

  • Be the first to like this

Functional Way

  1. 1. Functional Way
  2. 2. 自己紹介: lagénorhynque
  3. 3. (defprofile lagénorhynque [Kent OHASHI] :github/twitter @lagenorhynque :company 株式会社オプト :languages [Clojure Haskell Python Scala Go English français Deutsch русский] :interests [プログラミング 語学 数学])
  4. 4. 「フィボナッチ数」( )の計算を例にFibonacci number 関数型プログラミングの基本的な概念を紹介 1. 再帰(recursion) 2. 末尾再帰(tail recursion) 3. 高階関数(higher-order function) 4. 遅延評価(lazy evaluation)
  5. 5. フィボナッチ数 番目のフィボナッチ数 は、以下のように定義される。i Fi F0 F1 Fi = = = 0 1 + , i ≥ 2Fi−2 Fi−1 と続き、0, 1, 1, 2, 3, 5, 8, 13, 21, 34, . . . 直前の2項の和が次の項になっている。
  6. 6. 0. ループ 手続き型( )言語の基本パターンprocedural # Python def fibonacci(i): a, b = 0, 1 for n in range(i): a, b = b, a + b return a 副作用( ) 命令型( ) side e ect imperative
  7. 7. 変数やループ構造が目立ち、数学的な定義(プログラムの仕様)との関 係が分かりづらい 登場する変数が多くなったり、処理が複雑になったりすると、状態の 変化をたどるのが困難になりうる
  8. 8. 1. 再帰 ( )recursion 関数型( )言語の基本パターンfunctional -- Haskell fibonacci1 :: Int -> Integer fibonacci1 0 = 0 fibonacci1 1 = 1 fibonacci1 i = fibonacci1 (i - 2) + fibonacci1 (i - 1) ;; Clojure (defn fibonacci1 [i] (cond (= i 0) 0N (= i 1) 1N :else (+ (fibonacci1 (- i 2)) (fibonacci1 (- i 1))))) パターンマッチング( ) 宣言型( ) 参照透過性( ) pattern matching declarative referential transparency
  9. 9. 数学的な再帰的定義をほぼそのまま表現した、シンプルなコード 可変状態がないため状態の変化を管理する必要がなくなり、並列/並 行処理として実行するのも比較的容易 関数呼出しの繰り返しによりスタックオーバーフローが発生する可能 性がある フィボナッチ数の場合、同一の計算が繰り返されて計算量が指数的に 増大してしまう→メモ化( )を検討memoization
  10. 10. 2. 末尾再帰 ( )tail recursion 関数内部で最後に実行される処理が再帰呼出しになっている再帰 -- Haskell fibonacci2 :: Int -> Integer fibonacci2 i = fib i 0 1 where fib 0 a _ = a fib n a b = fib (n - 1) b (a + b) ;; Clojure (defn fibonacci2 [i] (letfn [(fib [n a b] (if (zero? n) a (recur (dec n) b (+ a b))))] (fib i 0N 1N)))
  11. 11. 多くの関数型言語では末尾再帰関数が末尾呼出し最適化(tail call optimization)により命令型のループと同等の処理に変換され、スタ ックオーバーフローが防止できる コードの処理内容も命令型ループによく似ている
  12. 12. 3. 高階関数 ( )higher-order function 引数として関数を受け取る、または戻り値として関数を返す関数 -- Haskell fibonacci3 :: Int -> Integer fibonacci3 i = fst $ foldl' fib (0, 1) [1..i] where fib (a, b) _ = (b, a + b) ;; Clojure (defn fibonacci3 [i] (letfn [(fib [[a b] _] [b (+ a b)])] (first (reduce fib [0N 1N] (range 0 i)))))
  13. 13. 典型的な繰り返し処理は抽象化されたライブラリの高階関数に任せ、 固有のロジックを持った関数の実装に集中することで、効率良くコー ディングすることができ、コードの可読性も向上する オブジェクト指向プログラミングのデザインパターンの多くは高階関 数によって同等の目的を果たせる
  14. 14. 4. 遅延評価 ( )lazy evaluation 式の評価を計算で必要になるまで遅らせる評価戦略 cf. 先行評価( )eager evaluation -- Haskell fibonacci4 :: Int -> Integer fibonacci4 i = fibs !! i where fibs = map fst $ iterate ((a, b) -> (b, a + b)) (0, 1) ;; Clojure (defn fibonacci4 [i] (let [fibs (map first (iterate (fn [[a b]] [b (+ a b)]) [0N 1N]))] (nth fibs i)))
  15. 15. -- Haskell fibonacci5 :: Int -> Integer fibonacci5 i = fibs !! i where fibs = 0 : 1 : zipWith (+) fibs (tail fibs) ;; Clojure (defn fibonacci5 [i] (letfn [(fibs [a b] (cons a (lazy-seq (fibs b (+ a b)))))] (nth (fibs 0N 1N) i)))
  16. 16. Haskellでは遅延評価がデフォルトの評価戦略 Clojureは先行評価が基本だが、遅延評価されるシーケンス(遅延シー ケンス)が利用できる 特に巨大なデータ構造や無限に続くデータ構造を扱う場合に、シンプ ルな定義と効率を両立させることができる
  17. 17. Further Reading Haskell 『プログラミングHaskell』 『すごいHaskellたのしく学ぼう!』 『関数プログラミング実践入門』 Clojure 『プログラミングClojure』 Exploring Clojure with Factorial Computation Scala 『Scalaスケーラブルプログラミング』 『Scala関数型デザイン&プログラミング』
  18. 18. Erlang 『すごいErlangゆかいに学ぼう!』 Elixir 『プログラミングElixir』 OCaml 『プログラミングの基礎』 cf. 今回の発表の元ネタ: BasicsOfFunctionalProgramming.md

×