Contenu connexe Plus de PIXELAcorporation (7) Introduction to Functional Programming3. Function
Type A => Type B へのマッピング
Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL.
3
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. ダイアグラム
Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL.
6
A BNormal
f
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. 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. 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. 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. 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. ダイアグラム
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. ダイアグラム
Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL.
13
A B
List[A] List[B]
Normal
Lifted
入力
f
f’
f’ を作るには?
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. ダイアグラム
Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL.
15
A B
List[A] List[B]
Normal
Lifted
入力
f
f’
List::flatMap
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. 表現方法の変換
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. 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
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. 例 日常のコード
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
}
25. 別の大問題 => Exception の存在
Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL.
25
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. 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. それぞれを
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. 連結できたら良くない?
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. ダイアグラム
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. ダイアグラム
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. 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. 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)
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. 演算子擬似コード
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. 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. ダイアグラム
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. 結合則条件
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が同値
これと、単位元の存在条件を満たすコンテナクラスの持つ特徴
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. List[Either[E, A]] が、 Either[E, List[A]] となるようにしたい。
Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL.
46
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. ちょっと脱線 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. 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. ダイアグラム 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]
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. 追加情報
○ 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. 所感
メリット:
○ FPはプログラムを統一型式で表現可能な手段を与えてくれる。
→ “統一“というプログラマがコーディング重要指標にあげる点を、徹底的に実現可能。
→ 言語を超えた統一表現
○ FPがもつ真のmodular性
デメリット:
学習コストの高さ
FP以外にも、FPと同様の統一型式表現手段があればそれを選択すれば良いですが、恐らくそれも学習コストの高さがあると思います。
結局 2択
皆さんが普段戦っている、プログラムを組む時の大問題”複雑性”に対して
* いわゆる普通の命令型の表現を選択して、一つ一つの処理は簡単だが、結果複雑で大きくなり易いコードを書いていく
or
* 高い学習コストを払ってでも新しい表現を選択し、複雑性を隠蔽できるコードを書いていくか
Copyright © PIXELA CORPORATION. All Rights Reserved.|PIXELA CORPORATION PROPRIETARY AND CONFIDENTIAL.
54