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

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

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

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

Avatar for Yuka O’oka

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 メソッドをもった型クラス