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

Option型を使いこなして初心者から中級者へ / scala fukuoka

Option型を使いこなして初心者から中級者へ / scala fukuoka

Scala福岡発表資料

KASUYA, Daisuke

May 28, 2016
Tweet

More Decks by KASUYA, Daisuke

Other Decks in Programming

Transcript

  1. ࣗݾ঺հ • 粕谷 大輔 • id:daiksy • @daiksy • 株式会社

    はてな • Mackerel開発チーム • Mackerelのニュースレターと 告知ブログの中の人です
  2. Scala教科書(基礎)の目次 (講義時間約2時間) • 参考文献 • 開発環境 & Hello World •

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

    varとvalとif式 • パターンマッチ • コレクション • Option型 • for式 • クラス定義 (case class, object, trait など) • implicit conversion/parameter • 型パラメータ • オブジェクト指向と関数プログラミング
  4. 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
  5. 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
  6. o.replace("Hello", "Hello World") <console>: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") }
  7. 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
  8. 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
  9. val o: Option[String] = Some("Hello") o: Option[String] = Some(Hello) o

    match { case Some(s) => s case None => "undefined" } res1: String = Hello
  10. val o: Option[Int] val i: Int o.map(_ * i) o

    が Some(5), i が 2の場合 => Some(10) o が None, i が 2の場合 => None
  11. val option1: Option[Int] val option2: Option[Int] option1.flatMap{ o1 => option2.map{

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

    o1 => option2.flatMap{ o2 => option3.map{ o3 => o1 * o2 * o3 } }
  13. 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 } } }
  14. for ( i <- (1 to 10) ) { println(i)

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

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

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

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

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

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

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

    to 10) } yield i * j (1 to 10).flatMap{ i => (1 to 10).map{ j => i * j } }
  22. 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)
  23. case class Custom(v: String) { def foreach(f: String => Unit):

    Unit = f(v) } for { c <- Custom("Fukuoka") } println(s“Hello $c”)
  24. 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
  25. 単純に下のように変換してしまうと実行時に MatchErrorが発生してしまう for { Seq(x, y, z) <- xs }

    yield x + y + z xs.map { case Seq(x, y, z) => x + y + z } しかし、上のfor式はエラーにならない。なぜか。
  26. この場合は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しないパターンは読み飛ばされる
  27. 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
  28. 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 } } }
  29. 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 スッキリ!!!!!!
  30. 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 が実行される 非同期処理
  31. 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