Slide 1

Slide 1 text

0QUJPOܕΛ࢖͍͜ͳ͠ ͯॳ৺ऀ͔Βதڃऀ΁ 4DBMB෱Ԭ

Slide 2

Slide 2 text

ࣗݾ঺հ • 粕谷 大輔 • id:daiksy • @daiksy • 株式会社 はてな • Mackerel開発チーム • Mackerelのニュースレターと 告知ブログの中の人です

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Scala教科書(基礎)の目次 (講義時間約2時間) • 参考文献 • 開発環境 & Hello World • varとvalとif式 • パターンマッチ • コレクション • Option型 • for式 • クラス定義 (case class, object, trait など) • implicit conversion/parameter • 型パラメータ • オブジェクト指向と関数プログラミング

Slide 7

Slide 7 text

Scala教科書(基礎)の目次 (講義時間約2時間) • 参考文献 • 開発環境 & Hello World • varとvalとif式 • パターンマッチ • コレクション • Option型 • for式 • クラス定義 (case class, object, trait など) • implicit conversion/parameter • 型パラメータ • オブジェクト指向と関数プログラミング

Slide 8

Slide 8 text

Option型 • nullの不便さからの卒業 (さらばヌルポ) • 値が存在しないかもしれない、という文脈を表 現 (Some or None)

Slide 9

Slide 9 text

val o: Option[String] = Some("Hello") o: Option[String] = Some(Hello) val o: Option[String] = None o: Option[String] = None val o: Option[String] = Option(null) o: Option[String] = None

Slide 10

Slide 10 text

val m = Map("key" -> "value") m: scala.collection.immutable.Map[String,String] = Map(key -> value) m.get("key") Option[String] = Some(value) m.get("hoge") Option[String] = None

Slide 11

Slide 11 text

Option型 • undefチェックが型によって強制される

Slide 12

Slide 12 text

o.replace("Hello", "Hello World") :12: error: value replace is not a member of Option[String] o.replace("Hello", "Hello World") ^ if (o.isDefined) { o.get.replace("Hello", "Hello World") }

Slide 13

Slide 13 text

Option型の値への アクセス • get • getOrElse • match式

Slide 14

Slide 14 text

val o = Some("Hello") o: Some[String] = Some(Hello) o.get String = Hello val o = None o: None.type = None o.get java.util.NoSuchElementException: None.get at scala.None$.get(Option.scala:347) ... 32 elided

Slide 15

Slide 15 text

val o = Some("Hello") o: Some[String] = Some(Hello) o.getOrElse("undefined") res4: String = Hello val o = None o: None.type = None o.getOrElse("undefined") res5: String = undefined

Slide 16

Slide 16 text

val o: Option[String] = Some("Hello") o: Option[String] = Some(Hello) o match { case Some(s) => s case None => "undefined" } res1: String = Hello

Slide 17

Slide 17 text

Option型の計算 • Optionは「値がない可能性」を文脈に持つ型 • Optionからいちいち値を取り出す必要はない • Option型のまま扱おう

Slide 18

Slide 18 text

Option型の計算 • 例1) Option[Int] と Intの計算

Slide 19

Slide 19 text

val o: Option[Int] val i: Int o.map(_ * i) o が Some(5), i が 2の場合 => Some(10) o が None, i が 2の場合 => None

Slide 20

Slide 20 text

Option型の計算 • 例2) Option[Int] と Option[Int]の計算

Slide 21

Slide 21 text

val option1: Option[Int] val option2: Option[Int] option1.flatMap{ o1 => option2.map{ o2 => o1 * o2 } } いずれかの値がNoneの場合 => None 両方値がある場合 => Some(o1 * o2)

Slide 22

Slide 22 text

Option型の計算 • 例3) Option[Int]が3つの時の計算

Slide 23

Slide 23 text

val option1: Option[Int] val option2: Option[Int] val option3: Option[Int] option1.flatMap{ o1 => option2.flatMap{ o2 => option3.map{ o3 => o1 * o2 * o3 } }

Slide 24

Slide 24 text

val option1: Option[Int] val option2: Option[Int] val option3: Option[Int] val option4: Option[Int] option1.flatMap{ o1 => option2.flatMap{ o2 => option3.flatMap{ o3 => option4.map{ o4 => o1 * o2 * o3 * 04 } } }

Slide 25

Slide 25 text

Option型の計算 • ネスト深すぎてつらい… • しかしつらくない書き方がある • その前に少し寄り道

Slide 26

Slide 26 text

for式

Slide 27

Slide 27 text

for式 • ループの制御構文 • Scalaのforはめっちゃ高機能

Slide 28

Slide 28 text

for ( i <- (1 to 10) ) { println(i) } val list = List(1, 2, 3, 4, 5) for ( i <- list) { println(i) } コレクションの要素をひとつずつ取り出して繰り返す

Slide 29

Slide 29 text

for ( i <- (1 to 10) if ( i % 2 == 0) ) { println(i) } ループ要素に対して if で条件を指定できる

Slide 30

Slide 30 text

for ( i <- (1 to 10)) yield i * 2 => Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20) for式自体が値をかえすことができる

Slide 31

Slide 31 text

for { i <- (1 to 10) j <- (1 to 10) } yield i * j forの入れ子はネストせずにフラットに書ける

Slide 32

Slide 32 text

for式 • これらのfor式は、実はコレクションのメソッド が呼ばれている

Slide 33

Slide 33 text

for ( i <- (1 to 10) ) { println(i) } (1 to 10).foreach ( println(_) )

Slide 34

Slide 34 text

for ( i <- (1 to 10) if ( i % 2 == 0) ) { println(i) } (1 to 10).filter( _ % 2 == 0).foreach( println(_) )

Slide 35

Slide 35 text

for ( i <- (1 to 10)) yield i * 2 => Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20) (1 to 10).map( _ * 2)

Slide 36

Slide 36 text

for { i <- (1 to 10) j <- (1 to 10) } yield i * j (1 to 10).flatMap{ i => (1 to 10).map{ j => i * j } }

Slide 37

Slide 37 text

foreach, withFilter(filter), flatMap(map) これらのメソッドが実装されているコレクションは for式に置き換えることができる

Slide 38

Slide 38 text

for式はコレクションに対するマクロのようなもの for式は内部的にforeachなどの呼び出しに変換される

Slide 39

Slide 39 text

以下のようにREPLを起動してみよう $ scala -Xprint:parser

Slide 40

Slide 40 text

scala> for (i <- 0 to 1) yield i + 1 (中略) val res0 = 0.to(1).map(((i) => i.$plus(1))) (中略) scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2)

Slide 41

Slide 41 text

for式はコンパイル時にコレクションのメソッド呼び出しに 変換される。 型チェックの前に変換されるので、for式内で使われている 値の型は関係ない(式展開後に型チェックが走る) 変換ルールは対象の値に変換可能なメソッドが実装されて いるかどうか

Slide 42

Slide 42 text

変換ルールは4種類

Slide 43

Slide 43 text

1. mapを定義している型では 1個のジェネレータで構成されたfor式を使える list.map(i => i * 2) for { i <- list } yield i * 2

Slide 44

Slide 44 text

2. mapの他にflatMapも定義している型では、複数のジェネ レータから構成されるfor式を使える list.flatMap{ i => list2.map { j => i * j } } for { i <- list j <- list2 } yield i * j

Slide 45

Slide 45 text

3. foreachを定義している型では、forループを使える (ジェネレータは1個でも複数でもよい) list.foreach { i => list2.foreach { j => println(i + j) } } for { i <- list j <- list2 } { println(i * j) }

Slide 46

Slide 46 text

4. withFilterを定義している型では、for式の中でifで始 まるフィルター式を使える list.withFilter(_ % 2 == 0).flatMap { i => list2.map { j => i * j } } for { i <- list if i % 2 == 0 j <- list2 } yield i * j

Slide 47

Slide 47 text

自分で実装してみよう

Slide 48

Slide 48 text

case class Custom(v: String) { def foreach(f: String => Unit): Unit = f(v) } for { c <- Custom("Fukuoka") } println(s“Hello $c”)

Slide 49

Slide 49 text

応用編: for式にパターンマッチが含まれる場合

Slide 50

Slide 50 text

val xs = List( Seq(1, 2), Seq(1, 2, 3), Seq(1, 2, 3, 4) ) for { Seq(x, y, z) <- xs } yield x + y + z

Slide 51

Slide 51 text

単純に下のように変換してしまうと実行時に MatchErrorが発生してしまう for { Seq(x, y, z) <- xs } yield x + y + z xs.map { case Seq(x, y, z) => x + y + z } しかし、上のfor式はエラーにならない。なぜか。

Slide 52

Slide 52 text

この場合はmapに加えてwithFilterが式展開される for { Seq(x, y, z) <- xs } yield x + y + z xs.withFilter { case Seq(x, y, z) => true case _ => false }.map { case Seq(x, y, z) => x + y + z } なのでmatchしないパターンは読み飛ばされる

Slide 53

Slide 53 text

Optionに話を戻そう

Slide 54

Slide 54 text

Optionに実装されているメソッド asInstanceOf flatMap isDefined orNull toRight canEqual flatten isEmpty productArity toString collect fold isInstanceOf productElement withFilter contains forall iterator productIterator exists foreach map productPrefix filter get nonEmpty toLeft filterNot getOrElse orElse toList

Slide 55

Slide 55 text

Option型 => 要素数が0または1のコレクション

Slide 56

Slide 56 text

Option型 => 要素数が0または1のコレクション => for式に置き換え可能

Slide 57

Slide 57 text

val option1: Option[Int] val option2: Option[Int] val option3: Option[Int] val option4: Option[Int] option1.flatMap{ o1 => option2.flatMap{ o2 => option3.flatMap{ o3 => option4.map{ o4 => o1 * o2 * o3 * 04 } } }

Slide 58

Slide 58 text

val option1: Option[Int] val option2: Option[Int] val option3: Option[Int] val option4: Option[Int] for { o1 <- option1 o2 <- option2 o3 <- option3 o4 <- option4 } yield o1 * o2 * o3 * o4 スッキリ!!!!!!

Slide 59

Slide 59 text

Optionやコレクション以外でforを使う例

Slide 60

Slide 60 text

val usdQuote = Future { connection.getCurrentValue(USD) } val jpyQuote = Future { connection.getCurrentValue(JPY) } val purchase = for { usd <- usdQuote jpy <- jpyQuote if isProfitable(usd, jpy) } yield connection.buy(amount, jpy) purchase onSuccess { case _ => println("OK") } USDとJPY両方の connection.getCurrentValue が完了したタイミ ングで connection.buy が実行される 非同期処理

Slide 61

Slide 61 text

val item1: Either[Error, Item] = validationItem1 val item2: Either[Error, Item] = validationItem2 for { i1 <- item1.right i2 <- item2.right } insertData(i1, i2) いずれかがLeft(Error)の場合、このfor式はLeft(Error)を かえす validation

Slide 62

Slide 62 text

for式を使いこなすと Scala中級者!!!

Slide 63

Slide 63 text

We are Hiring!! 東京 or 京都でエンジニア絶賛募集中 学生さんはインターンへのご応募ぜひ!!

Slide 64

Slide 64 text

͝ਗ਼ௌ ͋Γ͕ͱ͏͍͟͝·ͨ͠