$30 off During Our Annual Pro Sale. View Details »

Functional Programming

Yuuki Sumida
December 11, 2014

Functional Programming

合同勉強会 in 大都会岡山 -2014 Winter-
https://manage.doorkeeper.jp/groups/gbdaitokai/events/15289

Yuuki Sumida

December 11, 2014
Tweet

More Decks by Yuuki Sumida

Other Decks in Technology

Transcript

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

  2. ABOUT ME @razon 天領倉敷Scala 言い出しっぺ 岡山Javaユーザ会 幹事長 合同勉強会 in 大都会岡山

    座駆動LT大会 その他諸々 #I社
  3. ABOUT ME http://nemca.net/

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

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

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

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

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

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

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

  11. 手続きスタイルでのプログラミング 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 }
  12. 関数スタイルでのプログラミング val age = employees .filter(_.gender == Male) // 1

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

  14. コレクションの高階関数 val age = employees .filter(_.gender == Male) // 1

    .map(_.age) // 2 .fold((x, y) => if (x < y) x else y) // 3
  15. ここまでのまとめ 数学の「関数」の考え方をプログラミングに応用したもの 関数は計算結果を返す 「高階関数」によって関数の責務を更に効果的に分割する 小さくシンプルな「関数」を組み合わせて大きな処理をつ くる ひとつひとつの関数をわかりやすくする

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

  17. 状態と値の不変性

  18. STRINGの値は一体どこでおかしくなって しまったのか? public class A { String s = ...;

    public void foo() { // sの操作 } public void bar() { // sの操作 } } A a = new A(); a.foo(); a.bar();
  19. 変更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);
  20. 変更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();
  21. 注意:可変なデータ構造は伝搬する public class A { List<String> list = ...; public

    A foo() { // 新しいAのインスタンス内のリストも新しく作る必要がある } public A bar() { // 新しいAのインスタンス内のリストも新しく作る必要がある } } A a1 = new A(); A a2 = a1.foo(); A a3 = a2.foo();
  22. ここまでのまとめ 値を変更不可にすることによって、どこで間違ったかをわ かりやすくする 保持する値が増えるため、パフォーマンスに注意

  23. 副作用と参照透過性

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

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

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

  27. 宣言的なプログラミング 「どのように値を返すか」ではなく、「どのような値を返 すか」を記述するプログラミング 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
  28. ここまでのまとめ 副作用のないプログラミングを心がける 但し、完全に無くすのではなく、副作用のある箇所を限 定的にする 宣言的なプログラミングを心がける 手続き的な記述が必要な箇所と宣言的な記述を行う箇所 をうまく分ける

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

  30. パターンマッチ 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 }
  31. パターンマッチ 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" } <console>:12: warning: match is not exhaustive!
  32. パターンマッチ 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 + "さんは大人です" }
  33. カリー化と部分適用 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 = <function1> // g(y: Int) = 1 + y
  34. 遅延評価 val a = ... lazy val b = ...

    lazy val c = ... val d = ... // 条件によってbまたはcを使う
  35. 遅延評価による無限リスト 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))
  36. 再帰と末尾再帰最適化 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)
  37. この辺の本とか読んでみた らどうですかね Scalaスケーラブルプログラミング[コンセプト&コーディン グ] すごいHaskellたのしく学ぼう! プログラミングClojure Java開発者のための関数プログラミング 関数プログラミング実践入門

  38. おしまい