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.

Introduction to Functional Programming

814 views

Published on

Pixela Corporation

Published in: Software
  • My brother found Custom Writing Service ⇒ www.WritePaper.info ⇐ and ordered a couple of works. Their customer service is outstanding, never left a query unanswered.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Be the first to like this

Introduction to Functional Programming

  1. 1. Introduction to Functional Programming Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 株式会社ピクセラ 先端技術開発部 2019年08月19日
  2. 2. 関数とコンテナ型クラス Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 2
  3. 3. Function Type A => Type B へのマッピング Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 3
  4. 4. map (メソッドの方) Functionはマッピングなのに mapメソッド? Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 4
  5. 5. List::map List[1, 2, 3].map(i => i + 1) => List[2, 3, 4] Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 5
  6. 6. ダイアグラム Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 6 A BNormal f
  7. 7. ダイアグラム Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 7 A B List[A] List[B] Normal Lifted f List::map コンテナ層に適用可能にする
  8. 8. List List[A] = Head of List :: Tail of List Tail of List = (Head of (Tail of List)) :: (Tail of (Tail of List)) Tail of Tail of List = … Tail of Tail of … = Nil -> Head::TofHead::TTofHead::…Nil Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 8
  9. 9. List (scala的) sealed trait List[+A] case object Nil extends List[Nothing] case class Cons[+A](head: A, tail: List[A]) extends List[A] Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 9
  10. 10. fold[Right|Left] def foldRight[A, B](as: List[A], z:B)(f: (A, B) => B) : B = as match { case Nil => z case Cons(x, xs) => f(x, foldRight(xs, z)(f)) } @annotation.tailrec def foldLeft[A, B](as: List[A], z:B)(f: (B, A) => B) : B = as match { case Nil => z case Cons(x, xs) => foldLeft(xs, f(z, x))(f) } 関数fが多数回呼ばれる => fに副作用を入れないことがいかに重要か Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 10
  11. 11. Folds are primitive functions for List class def List::map[A, B](la:List[A])(f: A -> B) : List[B]= foldRight(Nil[List[B]])((h, t) => f(h) :: t)) Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 11
  12. 12. ダイアグラム Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 12 A B List[A] List[B] Normal Lifted 入力 f 入力がList[A]の場合、 f にある操作をして 出力をList[List[B]]ではなく、 List[B] にするには? List要素 1つ1つで List[B]ができるf
  13. 13. ダイアグラム Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 13 A B List[A] List[B] Normal Lifted 入力 f f’ f’ を作るには?
  14. 14. List::flatMap (scala) def append[A](la: List[A], lb: List[A]): List[A] = la match { case Nil => lb case Cons(h, t) => Cons(h, append(t, lb)) } def List::flatMap[A, B] (ls: List[A])(f: A => List[B]): List[B] = foldRight(ls, Nil:List[B])((h, t) => append(f(h), t)) Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 14
  15. 15. ダイアグラム Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 15 A B List[A] List[B] Normal Lifted 入力 f f’ List::flatMap
  16. 16. 命令型記述と関数型記述 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 16
  17. 17. Imperative Programming Style TypeA a = funAFromUnit(); TypeB b = funAToB(a); TypeC c = … Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 17
  18. 18. 表現方法の変換 chain(x:input, f: x => y) = f(input) chain(funAFromUnit(), a => chain(funAToB(a), b => chain(fun…))) Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 18
  19. 19. Functional Programming Style chain(funAFromUnit(), a => chain(funAToB(a), b => chain(fun…))) funAFromUnit() を入力とし、後続全てを丸ごとFunctionであると 捉えられる。 後続中も同様の構造となる。 == 再帰的 Imperative的表現 を Functional 的表現で再現した。 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 19
  20. 20. Functionalの有利な点 chain が function =>function中で操作が可能。 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 20
  21. 21. この有利な部分を有効に使いたい。 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 21
  22. 22. 例 日常のコード def proc_nest(a:A): C = { val b = funAtoB(a) if (isValid(b) == true) { val c = funBtoC(b) if (isValid(c) == true) c else Nothing } Nothing }
  23. 23. 例 日常のコード Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 23 def proc_flat(a: A) : C = { val b = funAtoB(a) if (isValid(b) != true) { Nothing } val c = funBtoC(b) if (isValid(c) != true) { Nothing } c }
  24. 24. 問題点 関数が本来やりたい記述が埋もれる Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 24
  25. 25. 別の大問題 => Exception の存在 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 25
  26. 26. Function的問題点 ○ 関数IF中にExceptionの情報は無い。 proc: A=>C Exceptionは副作用 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 26
  27. 27. ターゲット 関数本来の処理記述が埋もれさせず かつ (見た目上)例外を発生させない 表現にしたい Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 27
  28. 28. Railway Programming Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 28 元ネタ https://fsharpforfunandprofit.com/posts/recipe-part2/ Left(e) Right(b;B)a:A f sealed trait Either[+E, +A]{ … } case class Left[+E](value: E) extends Either[E, Nothing] case class Right[+A](value:A) extends Either[Nothing, A] Optionalの親戚的
  29. 29. Railway function Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 29 def railway[A, B, E](f: A => B): A => Either[E, B] = a => { try { if (a == Nothing) { Right(Nothing) } val result = f(a) if (isValid(result) == true) Right(result) else Right(Nothing) } catch(exception e) { Left(e) } }
  30. 30. それぞれを Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 30 Left(e) Right(c)b railway(funBtoC) Left(e) Right(b)a railway(funAtoB)
  31. 31. 連結できたら良くない? Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 31 Left(e) Right(c)b Left(e) Right(b)a しかし railway(funAtoB) と railway(funBtoC)の入出力の型式が違う railway(funAtoB) railway(funBtoC)
  32. 32. ダイアグラム Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 32 A B Either[E, B] Normal Lifted funAtoB railway(funAtoB) C Either[E, C] railway(funBtoC) funBtoC
  33. 33. ダイアグラム Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 33 A B Either[E, B] Normal Lifted funAtoB railway(funAtoB) C Either[E, C] railway(funBtoC) funBtoC Either::flatMap
  34. 34. flatMap 実装 sealed trait Either[+E, +A]{ def flatMap[EE >: E, B](f : A => Either[EE, B]): Either[EE, B] = this match { case Left(e) => Left(e) // * point case Right(a) => f(a) } Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 34
  35. 35. Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 35 Left(e) Right(c)Right(b) Left(e) Right(b)a railway(funAtoB) Either::flatMap(railway(funBtoC)) Left(e)
  36. 36. Left(e) Right(c) railway(funAtoB) railway(funBtoC)Either::flatMap a
  37. 37. railway(funAtoB) railway(funBtoC)Either::flatMap 一旦 Leftに分岐すると、 何も処理されずスルーされる。 Left(e) Right(c)a *point
  38. 38. 例 日常のコード 改 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 38 def proc_rail[A, C, E](a: A) : Either[E, C] = { Right(a).flatMap(a => railway(funAtoB)(a).flatMap(b => railway(funBtoC)(b))) }
  39. 39. 演算子擬似コード Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 39 def (>>=)[A,B,E](eith:Either[E, A])(f:A => Either[E, B]):Either[E, B] = { eith.flatMap(a => f(a)) }
  40. 40. Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 40 def proc_rail[A, C, E](a: A) : Either[E, C] = { Right(a) >>= railway(funAtoB) >>= railway(funBtoC) } 演算子>>= を使った擬似コード
  41. 41. ダイアグラム Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 41 A B Either[E, B] Normal Lifted railway(funAtoB) C Either[E, C] railway(funBtoC) Either[A, E]
  42. 42. 結合則条件 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 42 Right(a).flatMap(f).flatMap(g) == Right(a).flatMap(aa => f(aa).flatMap(g)) → flatMapの並列結合したものと、 ネストしたflatMapが同値 これと、単位元の存在条件を満たすコンテナクラスの持つ特徴
  43. 43. Monad! Monadは、計算の継続を抽象化したもの。 わかりやすい単語表現 “Chainable” flatMap は 別名 bind と言われることもある。 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 43
  44. 44. Either::map def Either::map[A, B](ea:Either[E, A])(f: A => B): Either[E, B] = ea.flatMap(a => Right(f(a))) Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 44
  45. 45. さらなる応用 List::map(la:List[A], f:A => Either[E, A]): List[Either[E, A]] List[Right[A], Left[E], Right[A], …] となる場合を考える。 この時、 Listの中にLeftが出てくることを許容できないケースがある とする。 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 45
  46. 46. List[Either[E, A]] が、 Either[E, List[A]] となるようにしたい。 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 46
  47. 47. map2 def Either::map2[E, A, B, C](ea: Either[E, A], eb: Either[E, B], f: (A, B) =>C) : Either[E, C] = ea.flatMap(a => eb.map(b => f(a, b) )) Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 47
  48. 48. ちょっと脱線 zip Either::zip[E, A, B](ea: Either[A], eb: Either[E, B]) : Either[E, (A, B)] = Either::map2(ea, eb) ((a, b) => (a, b)) Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 48
  49. 49. sequence Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 49 def sequence[E, A](es: List[Either[E, A]]): Either[E, List[A]] = es.foldRight[Either[E,List[A]]](Right(Nil))((head_e, tail_e) => Either::map2(head_e)(tail_e)((head, tail) => head::tail))
  50. 50. ダイアグラム sequence Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 50 A ANormal Either[A, E] List[Either[A, E]] Either[List[A], E] List[A, E]
  51. 51. まとめ ○ mapのような高階関数はListだけでなく、様々なコンテナ型クラスに実装可能 ○ 同じような計算表現の高階関数を定義できる。 ○ 命令型記述を関数型記述で実現可能となるだけでなく、行間に追加機能を持たせられる。 最上位の表現においては追加機能の詳細記述が隠蔽される。 ○ コンテナ型クラスを多層に出来、さらに層の入れ替えを実現する演算がある。 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 51
  52. 52. 追加情報 ○ 普段使うコンテナ型クラスはmonad性質がある。 → 普段のプログラムは、全てmonad性質を持つコンテナ型クラスで構成できる。 ○ List, Stream (遅延評価) ○ Optional(==Nullable), Either ○ State ○ Async, Parallel (︎↑を基本とし、さらに上位のライブラリを作れる。 例. テストライブラリ(テストデータ自動生成 & データに対する性質テスト) パーサーライブラリ(500行程度でパーサーライブラリ&Jsonパーサ合わせたものがかけます) ○ Reader-monad, Writer-Monad, IO-Monad 等もある ○ Monad(継続 == 命令型的記述)に関連して、関数型言語では、特別な記述様式が用意されている Haskell : do記法, Scala: for記法, F#: computation記法 Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 52
  53. 53. 追加情報 ○ unit, flatMap をprimitiveとして、上位Combinatorを実装可能なものが多い。 ○ map, mapN, zip, sequnence, transverse… ○ unit, map2 をprimitiveにすることも可能 primitiveの選択性) ○ コンテナ型クラスのメソッドがある規則を満たせば、それらクラスがさらに抽象的なグループに分別できる 例 Functor 属性 map に対する規則 containr::map[A](c:container, f: A => A) について、 container::map(c, (a => a)) == a が成立するもの ○ 演算に対しても同様にグループ分けもできる。 例 Monoid 属性 結合則 op(op(x, y), z) == op(x, op(y, z)) と単位元 の存在 実例 String , List の加算 => foldable との関係性につながる Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 53
  54. 54. 所感 メリット: ○ FPはプログラムを統一型式で表現可能な手段を与えてくれる。 → “統一“というプログラマがコーディング重要指標にあげる点を、徹底的に実現可能。 → 言語を超えた統一表現 ○ FPがもつ真のmodular性 デメリット: 学習コストの高さ FP以外にも、FPと同様の統一型式表現手段があればそれを選択すれば良いですが、恐らくそれも学習コストの高さがあると思います。  結局 2択 皆さんが普段戦っている、プログラムを組む時の大問題”複雑性”に対して * いわゆる普通の命令型の表現を選択して、一つ一つの処理は簡単だが、結果複雑で大きくなり易いコードを書いていく or * 高い学習コストを払ってでも新しい表現を選択し、複雑性を隠蔽できるコードを書いていくか Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL. 54
  55. 55. 参考書 & 参考サイト https://www.manning.com/books/functional-programming-in-scala https://fsharpforfunandprofit.com

×