Upgrade to Pro — share decks privately, control downloads, hide ads and more …

(Ruby使いのための)Scalaで学ぶ関数型プログラミング

 (Ruby使いのための)Scalaで学ぶ関数型プログラミング

Yuka O’oka

October 23, 2013
Tweet

More Decks by Yuka O’oka

Other Decks in Programming

Transcript

  1. 自己紹介 自己紹介 おおかゆか ( おおかゆか (id: oukayuka id: oukayuka) )

    フリーランスのWebプログラマ。 元々はPHPerでしたが、最近はもっぱらRails案件を 生業に活動中。 Scalaに手を出したのは、ほんの3ヶ月ほど前。 エンジニアがお金について考えるためのrake:money rake:money という勉強会を主宰してます。月1の頻度で都内にて 開催しているので、興味があればどうぞ。 http://groups.google.co.jp/group/rakemoney
  2. Rubyは「acceptable Lisp」とか「MatzLisp」と 揶揄されることもあるくらい、Lispからの影響 が強い言語である。 Ruby使いがより一歩ステップアップするため にLispを学ぼうとはよく言われるところ。 Eric Raymond も Paul

    Grahamも、ことあるご とにLispを薦めてくる。 しかしMatzも認めるように、Lispは普通の人 には扱いきれない習得コストの高い言語。 よい よいRuby Ruby使いになるために 使いになるために
  3. 1-1. 1-1. 変数の定義 変数の定義 ▪var(変数)型 var 変数名:型=値 例) > var

    n: Int = 1 ☞n: Int = 1 > n = 3 ☞n: Int = 3 ▪val(値)型 val 変数名:型=値 例) > val n: Int = 1 ☞n: Int = 1 > n = 3 ☞error: reassginment to val 再代入できない! ≪Scalaちゃん推奨≫ ≪使ったらある意味負け≫
  4. > val n: Int = 1 ☞n: Int = 1

    1-2. 1-2. 代表的な型 代表的な型 > val str: String = ”hoge” ☞str: java.lang.String = hoge 数値 文字列 > val sym: Symbol = 'piyo ☞sym: Symbol = 'piyo シンボル > val l: List[Int] = List(1,2,3) ☞l: List[Int] = List(1,2,3) リスト
  5. def 関数名(引数名:型, …):返り値の型 = { 処理内容 } 例) > def

    max(x: Int, y: Int): Int = { | if (x < y) y else x | } > max(8, 3) ☞res1: Int = 8 1-3. 1-3. 関数の定義 関数の定義
  6. 変数や関数の返り値の型宣言は、コンパイラ が推測できる限りにおいて省略 省略できる! 1-4. 1-4. 型推論 型推論 例) > val

    i = 4 ☞i: Int = 4 > val d = List(0.1, 1.2, 3.4) ☞d: List[Double] = List(0.1, 1.2, 3.4) > def hello = ”Hello, World!” ☞hello: java.lang.String
  7. 1-5. 1-5. 制御構文 制御構文(1) - if (1) - if if

    (条件文1) 値1 else if (条件文2) 値2 … else 値3 例) > if (str.size < 3) { | ”It's short.” | } else if (str.size < 6) { | ”Not so long.” | } else ”It's long.” ☞res1: java.lang.String = It's long. 必ず値を返すことに注意!
  8. 1-6. 1-6. 制御構文 制御構文(2) - for (2) - for for

    (ブロック引数 <- コレクション; …) 処理内容 for (ブロック引数 <- コレクション; …) yield 値 例) > for (i <- 1 to 9) print(i + ” ”) ☞1 2 3 4 5 6 7 8 9 > for (i <- (1 to 9).toList) yield i + 1 ☞res1: List[Int] = List(2,3,4,5,6,7,8,9,10) > for (i <- 1 to 2; j <- 1 to 3) print("[" + i + "," + j + "]") ☞[1,1][1,2][1,3][2,1][2,2][2,3] 外2回、内3回の 二重ループ
  9. 2-1. 2-1. 高階関数 高階関数 例) > List(1,2,3).map(n => n +

    1) ☞res1: List[Int] = List(2,3,4) > List(1,2,3,4,5).filter(n => n % 2 == 0) ☞res2: List[Int] = List(2, 4) > List(1,2,3,4).map(_ * 2) ☞res3: List[Int] = List(2,4,6,8) Rubyのmapやsortメソッドのように、関数を引数に とる関数のこと。 魔法の「_」(アンダーバー)
  10. 2-2. 2-2. クロージャ クロージャ (引数:型,…) => 値 例) > val

    sq = (n: Int) => Math.pow(n, 2).toInt > sq(6) ☞res1: Int = 36 > List(1,2,3,4,5).map(sq) ☞res2: List[Int] = List(1,4,9,16,25) 名前を定義せずに作成した関数のこと。「無名関 無名関 数 数」とも言う。変数に代入可。 定義したクロージャ を変数sqに代入
  11. 2-3. 2-3. 関数と変数は等価 関数と変数は等価 例) > val half = (n:

    Int) => n / 2 ☞half: (Int) => Int = <function> > half(14) ☞res1: Int => 7 > def quartize(n: Int) = n / 4 > val quarter = quartize _ > quarter(20) ☞res1: Int => 5 仮引数を「_」で表記 (_)のカッコは省略可
  12. 2-4. 2-4. パターンマッチング パターンマッチング(1) (1) 引数 match { case パターン1

    => 処理1 or 値1 : case _ => 処理x or 値x } 例) > val str = ”world” > str match { | case ”world” => println(”Hello!”) | case _ => () | } ☞Hello! その他のケースは「_」にマッチ
  13. 2-5. 2-5. パターンマッチング パターンマッチング(2) (2) 例) > List(1,2,3) match {

    | case List(a, b, c) => a + b + c | case _ => 0 } ☞res1: Int = 6 > val v: Any = ”hoge” > v match { | case i: Int => i * 100 | case s: String => s.size | } ☞res2: Int = 4 変数a,b,cに値を束縛 型のマッチ
  14. 2-6. 2-6. 再帰関数 再帰関数 例) > def sumLoop(n: Int) =

    { | var total = 0 | for (i <- 1 to n) total += i | total | } > def sumRecursive(n: Int): Int = n match { | case 1 => 1 | case _ => n + sumRecursive(n - 1) | } > (sumLoop(10), sumRecursive(10)) ☞res1: (Int, Int) = (55,55) ループ型 再帰型 返り値の型宣言 が必要!
  15. 2-7. 2-7. カリー化 カリー化 例) > def multi(n: Int)(m: Int)

    = m * n > multi(6)(9) ☞res1: Int = 54 > def multiTwo = multi(2)_ > multiTwo(5) ☞res2: Int = 10 複数の引数をとる関数を、引数が「元の関数の最初 の引数」で返り値が「元の関数の残りの引数をとり結 果を返す関数」であるような関数にすること。 引数nに2を代入 mはそのまま仮引数 として渡す
  16. 2-8. 2-8. 遅延評価 遅延評価 例) > class SchrodingerCat { |

    lazy val status = { | println("Here open a box..."); "Alive!" | } | } > val cat = new SchrodingerCat > cat.status ☞Here open a box... ☞res1: java.lang.String = Alive! オブジェクトのフィールドの評価を、初期化時ではなく 参照時に行うようにする。 まだstatusが評価されてない ここで初めてstatusが評価される!
  17. 3-1. Implicit Conversion 3-1. Implicit Conversion 例) > class Cat

    > class Man { def greet = ”Hello!” } > implicit def cat2man(c: Cat): Man = new Man > val cat = new Cat > cat.greet ☞res1: java.lang.String = Hello! Rubyはオープンクラスなので既存のクラスを自由に上書 きできる。しかしScalaは厳密な静的型付け言語のため同 じことはできない。しかし暗黙の型変換 暗黙の型変換を使えば、おおよ その場合その目的を達成できる。 瞬間的にCatオブジェクトが Manオブジェクトに変身!
  18. 3-2. Structural Subtyping 3-2. Structural Subtyping 例) > class Cat

    > class Duck { | def swim = () | def quack = "Quaaa!" | } > def duckTest[T](x: T { def swim; def quack: String }) = "You're a duck!" > duckTest(new Duck) ☞res1: java.lang.String = You're a duck! > duckTest(new Cat) ☞<console>: error: type mismatch Scalaでダックタイピング ダックタイピングっぽいことをやるための仕組み。 Tはswimメソッドとquack メソッドをもった型クラス