Slide 1

Slide 1 text

"FUN"CTIONAL PROGRAMMING 2014/12/13(Sat) 合同勉強会 in 大都会岡山 -2014 Winter-

Slide 2

Slide 2 text

ABOUT ME @razon 天領倉敷Scala 言い出しっぺ 岡山Javaユーザ会 幹事長 合同勉強会 in 大都会岡山 座駆動LT大会 その他諸々 #I社

Slide 3

Slide 3 text

ABOUT ME http://nemca.net/

Slide 4

Slide 4 text

本編の前におまけの話 「型付け」について

Slide 5

Slide 5 text

「動的型付き言語」と「静的型付き言 語」の話

Slide 6

Slide 6 text

AGENDA 関数プログラミングって何なの? 今すぐ始められる関数プログラミング "関数型言語"での関数プログラミング モナ…の話はしません

Slide 7

Slide 7 text

関数プログラミング って何なの?

Slide 8

Slide 8 text

数学の関数 入力(引数)に関数を作用させて結果を求める y = f(x)

Slide 9

Slide 9 text

「関数」を組み合わせて値を求める y = g(f(x)) y = (g ○ f)(x)

Slide 10

Slide 10 text

EX)男性社員のうち、一番若い社員の年 齢が知りたい 1. 社員情報から男性の社員のみを抽出する関数 2. 年齢が一番若い社員情報を取得する関数 3. 社員情報から年齢を取得する関数

Slide 11

Slide 11 text

手続きスタイルでのプログラミング int age = Integer.MAX; for (Employee employee: employees) { if (employee.getGender() == Gender.Male) { // 1 if (employee.getAge() < age) { // 2 age = employee.getAge(); // 3 } // 2 } // 1 }

Slide 12

Slide 12 text

関数スタイルでのプログラミング val age = employees .filter(_.gender == Male) // 1 .map(_.age) // 2 .min // 3

Slide 13

Slide 13 text

高階関数 employees .filter(_.gender == Male) 1. 条件を満たすものを抽出する関数 2. 社員の性別が男性か判定する関数 1の引数として2(関数)を渡している

Slide 14

Slide 14 text

コレクションの高階関数 val age = employees .filter(_.gender == Male) // 1 .map(_.age) // 2 .fold((x, y) => if (x < y) x else y) // 3

Slide 15

Slide 15 text

ここまでのまとめ 数学の「関数」の考え方をプログラミングに応用したもの 関数は計算結果を返す 「高階関数」によって関数の責務を更に効果的に分割する 小さくシンプルな「関数」を組み合わせて大きな処理をつ くる ひとつひとつの関数をわかりやすくする

Slide 16

Slide 16 text

今すぐ始められる 関数プログラミング

Slide 17

Slide 17 text

状態と値の不変性

Slide 18

Slide 18 text

STRINGの値は一体どこでおかしくなって しまったのか? public class A { String s = ...; public void foo() { // sの操作 } public void bar() { // sの操作 } } A a = new A(); a.foo(); a.bar();

Slide 19

Slide 19 text

変更1:クラスの状態をなくす public class A { public static String foo(String s) { // 新しい文字列を返す } public static String bar(String s) { // 新しい文字列を返す } } String s1 = ...; String s2 = A.foo(s1); String s3 = A.foo(s2);

Slide 20

Slide 20 text

変更2:クラスを不変な値クラスにする public class A { String s = ...; public A foo() { // 新しいAのインスタンスを作って返す } public A bar() { // 新しいAのインスタンスを作って返す } } A a1 = new A(); A a2 = a1.foo(); A a3 = a2.foo();

Slide 21

Slide 21 text

注意:可変なデータ構造は伝搬する public class A { List list = ...; public A foo() { // 新しいAのインスタンス内のリストも新しく作る必要がある } public A bar() { // 新しいAのインスタンス内のリストも新しく作る必要がある } } A a1 = new A(); A a2 = a1.foo(); A a3 = a2.foo();

Slide 22

Slide 22 text

ここまでのまとめ 値を変更不可にすることによって、どこで間違ったかをわ かりやすくする 保持する値が増えるため、パフォーマンスに注意

Slide 23

Slide 23 text

副作用と参照透過性

Slide 24

Slide 24 text

副作用 ある関数において、関数外の何かしらの要素に影響を与え るようなもの ファイルIO DBの更新 インスタンスの状態やグローバル変数の操作

Slide 25

Slide 25 text

参照透過性 同じ引数を与えれば必ず同じ結果が得られる性質 関数外の関数外の何かしらの要素に影響を与えない

Slide 26

Slide 26 text

副作用とどう付き合うか 「副作用」をなくすのではなく、「副作用」を持つ箇所を 限定的にする 破壊的に操作したほうがやりやすいこともあるので

Slide 27

Slide 27 text

宣言的なプログラミング 「どのように値を返すか」ではなく、「どのような値を返 すか」を記述するプログラミング int age = Integer.MAX; for (Employee employee: employees) { if (employee.getGender() == Gender.Male) { if (employee.getAge() < age) { age = employee.getAge(); } } } val age = employees .filter(_.gender == Male) .map(_.age) .min

Slide 28

Slide 28 text

ここまでのまとめ 副作用のないプログラミングを心がける 但し、完全に無くすのではなく、副作用のある箇所を限 定的にする 宣言的なプログラミングを心がける 手続き的な記述が必要な箇所と宣言的な記述を行う箇所 をうまく分ける

Slide 29

Slide 29 text

"関数型言語"での 関数プログラミング

Slide 30

Slide 30 text

パターンマッチ enum Gunpla {HG, MG, PG, RG, RE_100} Gumpla g = Gunpla.RE_100; switch (g) { case HG: case MG: // foo break; default: // bar } if (g == Gunpla.HG) { // foo } else if (g == Gunpla.MG) { // bar } else { // baz }

Slide 31

Slide 31 text

パターンマッチ abstract sealed class Gunpla case object HG extends Gunpla case object MG extends Gunpla case object PG extends Gunpla case object RG extends Gunpla case object RE_100 extends Gunpla val hg: Gunpla = HG hg match { case HG => "HG" case MG => "MG" } :12: warning: match is not exhaustive!

Slide 32

Slide 32 text

パターンマッチ case class Person(name: String, age: Int) val john = Person("John Doe", 31) john match { case Person(name, age) if age < 20 => name + "さんは子供です" case Person(name, _) => name + "さんは大人です" }

Slide 33

Slide 33 text

カリー化と部分適用 f: (X × Y) -> Z g: X -> (Y -> Z) def f1(x: Int, y: Int) = x + y def f2(x: Int)(y: Int) = x + y val g = f2(1)_ g: Int => Int = // g(y: Int) = 1 + y

Slide 34

Slide 34 text

遅延評価 val a = ... lazy val b = ... lazy val c = ... val d = ... // 条件によってbまたはcを使う

Slide 35

Slide 35 text

遅延評価による無限リスト def iterate[T](f:T => T, x:T):Stream[T] = Stream.cons(x, iterate(f, f(x))) iterate((x:Int) => x + 1, 1) // 1から開始で、+1ずつされていく無限リスト .take(10) // 10要素取得 .toList // リスト化(この時点で初めて評価されてリストになる) // List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) val codename = List("Playground", "Kestrel", "Merlin", "Tiger", "Mustang", "Dolphin") iterate((x:Int) => x + 1, 1) .zip(codename) .toList // List[(Int, String)] = // List((1,Playground), (2,Kestrel), (3,Merlin), // (4,Tiger), (5,Mustang), (6,Dolphin))

Slide 36

Slide 36 text

再帰と末尾再帰最適化 def iterate[T](f:T => T, x:T):Stream[T] = Stream.cons(x, iterate(f, f(x))) iterate((x:Int) => x + 1, 1) // 1から開始で、+1ずつされていく無限リスト .take(10) // 10要素取得 .toList // リスト化(この時点で初めて評価されてリストになる) // List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

Slide 37

Slide 37 text

この辺の本とか読んでみた らどうですかね Scalaスケーラブルプログラミング[コンセプト&コーディン グ] すごいHaskellたのしく学ぼう! プログラミングClojure Java開発者のための関数プログラミング 関数プログラミング実践入門

Slide 38

Slide 38 text

おしまい