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

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

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

7306d1333cb52f957f87017d175daa43?s=128

Yuka O’oka

October 23, 2013
Tweet

More Decks by Yuka O’oka

Other Decks in Programming

Transcript

  1. Scala Scalaで学ぶ で学ぶ 関数型プログラミング 関数型プログラミング Ruby使いのための Presented by おおかゆか

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

    フリーランスのWebプログラマ。 元々はPHPerでしたが、最近はもっぱらRails案件を 生業に活動中。 Scalaに手を出したのは、ほんの3ヶ月ほど前。 エンジニアがお金について考えるためのrake:money rake:money という勉強会を主宰してます。月1の頻度で都内にて 開催しているので、興味があればどうぞ。 http://groups.google.co.jp/group/rakemoney
  3. Scalaって何?という方は、これを読 む前にまず 「Ruby使いのための Scalaのススメ」 をご一読ください。 ☞http://ja.verbmode.net/2009/10/03/   recommend_of_scala_for_rubyist ≪ ≪注意≫

    注意≫
  4. Rubyは「acceptable Lisp」とか「MatzLisp」と 揶揄されることもあるくらい、Lispからの影響 が強い言語である。 Ruby使いがより一歩ステップアップするため にLispを学ぼうとはよく言われるところ。 Eric Raymond も Paul

    Grahamも、ことあるご とにLispを薦めてくる。 しかしMatzも認めるように、Lispは普通の人 には扱いきれない習得コストの高い言語。 よい よいRuby Ruby使いになるために 使いになるために
  5. それでもScalaなら…、Scalaならきっと何とかしてく れる。というのも、Scalaは最もRubyに似た関数型 言語だから。 Rubyと同じくALGOL系の文法を持つScalaは、関 数型言語のエッセンスを全て備えながら、Rubyと 同じく徹底したオブジェクト指向言語でもある。 Scalaこそが、Ruby使いが関数型プログラミングを 学ぶのに最も適した言語と言えよう。 Scalaを学べば、きっとよりよいRuby使いになれる はずである…たぶん。

    そこで そこでScala Scalaですよ ですよ
  6. まずはScala の文法の基礎 から 魔法少女Scalaちゃん ©2009 熊ジェット ➀

  7. 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ちゃん推奨≫ ≪使ったらある意味負け≫
  8. > 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) リスト
  9. def 関数名(引数名:型, …):返り値の型 = { 処理内容 } 例) > def

    max(x: Int, y: Int): Int = { | if (x < y) y else x | } > max(8, 3) ☞res1: Int = 8 1-3. 1-3. 関数の定義 関数の定義
  10. 変数や関数の返り値の型宣言は、コンパイラ が推測できる限りにおいて省略 省略できる! 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
  11. 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. 必ず値を返すことに注意!
  12. 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回の 二重ループ
  13. 関数型プログラ ミングいくよー 魔法少女Scalaちゃん ©2009 熊ジェット ➁

  14. 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メソッドのように、関数を引数に とる関数のこと。 魔法の「_」(アンダーバー)
  15. 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に代入
  16. 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 仮引数を「_」で表記 (_)のカッコは省略可
  17. 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! その他のケースは「_」にマッチ
  18. 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に値を束縛 型のマッチ
  19. 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) ループ型 再帰型 返り値の型宣言 が必要!
  20. 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はそのまま仮引数 として渡す
  21. 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が評価される!
  22. せめて、 せめて、Ruby Ruby っ っ ぽ ぽ く く 魔法少女Scalaちゃん

    ©2009 熊ジェット ➌ 第参最終章
  23. 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オブジェクトに変身!
  24. 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 メソッドをもった型クラス
  25. 以上です。 もっとScalaを詳しく 知りたくなった人は、 コップ本買ってね。 魔法少女Scalaちゃん ©2009 熊ジェット 『Scalaスケーラブルプログラミング』 (通称:コップ本)