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

scalaz.\/ が便利だった話

scalaz.\/ が便利だった話

9b888a029ae98abd2675b115ff0c4256?s=128

Rikito Taniguchi

July 10, 2016
Tweet

Transcript

  1. scalaz.\/ ͕ศརͩͬͨ࿩ ୈࡾճscalaؔ੢ษڧձ 2016-07-10

  2. ࠓ೔͸ scala.Either ͱ scalaz.\/ ͷҧ͍ʹ͍ͭͯ࿩Λ͠·͢

  3. scalaz ͷ࿩ͱ͍͏ΑΓ͸ scala.Either ͷ͓͔͠ͳڍಈ΍ scalaz.\/ Ͱͷղܾํ๏Λݟ͍ͯ͘

  4. http://www.irasutoya.com/2013/11/blog-post_5898.html ҧ࿨ײײͨ͡Β ͭͬ͜Έ͓ئ͍͠·͢ʂ

  5. ཧ࿦ͬΆ͍࿩͸͋·Γ͠ͳ͍ ࣮ફ(࣮૷)ʹΑͬͨ࿩Λ ͢Δͧʂʂʂʂʂʂ

  6. ͓͠ͳ͕͖ 1. ࣗݾ঺հ 2. scala.Either ֓ཁ 3. scala.Either ͷෆศ 4.

    ෆศͷݪҼ 5. scalaz.\/
  7. ࣗݾ঺հ ୩ޱ ྗే @tanishiking id: tanishiking24 ɾژ౎େֶͰֶੜ΍ͬͯ·͢ ɾ࠷ۙ͸ͯͳΞϧόΠτ ɾڵຯͱͯ͠͸ ɹɹɾ

    MySQL ɹɹɾ Python / Scala / shell script Scalaྺ: 6ϲ݄͘Β͍?
  8. ઌʹ·ͱΊ ɾscala.Either ʹ͸ෆࣗવͳڍಈ͕͍͔ͭ͋͘Δ ɾͦͷҰͭͷղܾࡦͱͯ͠ scalaz.\/ Λ࢖͏ͱ͍͏બ୒ࢶ͕ ͋Δ ɾ؆୯ͳͱ͜Ζ(\/)͔Β scalaz ࢖͍ͬͯ͘ͷ͸ྑͦ͞͏

    ɾศརͳͱ͜Ζ͚ͩ࢖͓͏ʂ ɾେࣄͳͷ͸ scala.Either ͷڍಈΛ஌͓ͬͯ͘͜ͱʂ
  9. ͓͠ͳ͕͖ 1. ࣗݾ঺հ 2. scala.Either ֓ཁ 3. scala.Either ͷෆศ 4.

    ෆศͷݪҼ 5. scalaz.\/
  10. Either ɾscalaඪ४ ɾOptionܕͰnull͔΋͠Εͳ͍ͱ͍͏จ຺ΛදݱͰ͖ͨ ɾྫ֎͕౤͛ΒΕΔͳͲͯ͠ॲཧ͕ࣦഊͨ͠৔߹΋NoneΛฦ͢ʁ ɾ(NoneͩͱΤϥʔ΍ྫ֎ͷ৘ใ͕ࣦΘΕΔ…) ɾEither[A, B]Λ࢖͏͜ͱͰܕ͕A͔B͔ͱ͍͏දݱ͕࣮ݱͰ͖Δ ɾAʹErrorΛ֨ೲͯ͋͛ͨ͠Γ

  11. Either ɾEither͸ந৅ΫϥεͰɺͦͷαϒΫϥεͱͯ͠Left,RightΛ࣋ͬͯΔ ɾRightʹਖ਼ৗ஋ɺLeftʹࣦഊͨ࣌͠ͷҟৗ஋ sealed abstract class Either[+A, +B] extends Product

    with Serializable final case class Left[+A, +B](a: A) extends Either[A, B] final case class Right[+A, +B](b: B) extends Either[A, B] https://github.com/scala/scala/blob/d6f66ec0f38e42c19f79cbe9d32d29c65dee1e05/src/library/scala/util/ Either.scala#L69 https://github.com/scala/scala/blob/d6f66ec0f38e42c19f79cbe9d32d29c65dee1e05/src/library/scala/util/ Either.scala#L182-L202
  12. Either def parseInteger(numStr: String): Either[NumberFormatException, Int] = { try {

    Right(numStr.toInt) } catch { case e: NumberFormatException => Left(e) } } ྫ֎Λ&JUIFSͰϥοϓͯ͠ΈͨΓ
  13. Either ɾEitherຊମʹ͸ map / flatMap ͱ͍ͬͨϝιου͸ ੜ͑ͯͳ͍ʂʂʂ ɾ(Right|Left)Projectionͱ͍͏ܕʹੜ͑ͯΔ ɾrightϝιουͰม׵ scala>

    Right(“12").right.flatMap(parseInteger) res2: scala.util.Either[NumberFormatException,Int] = Right(12) scala> Right(“tanishi").right.flatMap(parseInteger) res3: scala.util.Either[NumberFormatException,Int] = Left(java.lang.NumberFormatException: For input string: "tanishi")
  14. Either for-comprehension΋͜Μͳײ͡Ͱ for { rawId <- Right("12").right id <- parseInteger(rawId).right

    } yield id
  15. ศརʂʂ

  16. ͓͠ͳ͕͖ 1. ࣗݾ঺հ 2. scala.Either ֓ཁ 3. scala.Either ͷෆศ 4.

    ෆศͷݪҼ 5. scalaz.\/
  17. EitherศརͳͷͰ͕͢ ͍͔ͭ͘ෆศͳڍಈ͕…

  18. Either - ֬ೝ scala ͷ forࣜ͸ίϯύΠϧ࣌ʹ಺෦తʹ map / flatMap /

    withFilter / filter / foreach ͱ͍ͬͨϝιουͷ૊Έ߹Θͤʹม׵͞ΕΔ
  19. Ұͭ໨ for { a <- Right(1).right b = a +

    1 } yield b
  20. for-comprehensionͰ ୅ೖͬΆ͍͜ͱ͕Ͱ͖ͳ͍ for { a <- Right(1).right b = a

    + 1 } yield b <console>:24: error: value map is not a member of Product with Serializable with scala.util.Either[Nothing,(Int, Int)] a <- Right(1).right FJUIFS͔Βग़͖ͯͨ஋Λӈࣜʹ࣋ͭ࣌
  21. ೋͭ໨ for { (a, b) <- Right((1, 2)).right } yield

    a + b
  22. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ for { (a, b) <- Right((1, 2)).right }

    yield a + b <console>:19: error: constructor cannot be instantiated to expected type; found : (T1, T2) required: scala.util.Either[Nothing,(Int, Int)] (a, b) <- Right((1, 2)).right ^
  23. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ (for { a <- Right(1).right if a >

    0 } yield a) match { case Right(num) => println(num) case Left(_) => println("left!!") } <console>:28: error: constructor cannot be instantiated to expected type; found : scala.util.Right[A,B] required: Option[scala.util.Either[Nothing,Int]] case Right(n) => println(n) ύλʔϯϚον͡Όͳ͍͚Ͳ͜Ε΋μϝ
  24. ͪͳΈʹ྆ํͱ΋ OptionͰ͸࣮ݱͰ͖Δ for { (a, b) <- Some((1, 2)) }

    yield a + b res0: Option[Int] = Some(3) for { a <- Some(1) b = a + 1 } yield b res1: Option[Int] = Some(2)
  25. ͓͠ͳ͕͖ 1. ࣗݾ঺հ 2. scala.Either ֓ཁ 3. scala.Either ͷෆศ 4.

    ෆศͷݪҼ 5. scalaz.\/
  26. scala -Xprint:parser(typer)

  27. ֬ೝ scala.Either ΍ scalaz.\/ ʹ͸ withFilter ͕࣮૷ ͞Ε͓ͯΒͣ withFilter ͷ୅ΘΓʹ

    filter ͕࢖༻͞ ΕΔ ࠓճͷ࿩Ͱ͸ filter ͱ withFilter ͷҧ͍͸ॏཁͰ͸ ͳ͍ͷͰ໨ΛͭΉΓ·͢
  28. for-comprehensionͰ ୅ೖͬΆ͍͜ͱ͕Ͱ͖ͳ͍ for { a <- Right(1).right b = a

    + 1 } yield b ͍͍ͩͨ͜Μͳײ͡ʹͳΔͬΆ͍ Right(1).right.map(a => { val b = a + 1; (a, b) }).map(_ match { case ((a, b)) => b })
  29. for-comprehensionͰ ୅ೖͬΆ͍͜ͱ͕Ͱ͖ͳ͍ Right(1).right.map(a => { val b = a +

    1; (a, b) }).map(_ match { case ((a, b)) => b }) ͜͜ͷฦΓ஋͸ Right((1, 2))
  30. for-comprehensionͰ ୅ೖͬΆ͍͜ͱ͕Ͱ͖ͳ͍ Right(1).right.map(a => { val b = a +

    1; (a, b) }).map(_ match { case ((a, b)) => b }) ͜͜ͷฦΓ஋͸ Right((1, 2)) map ΍ flatMap ͕ੜ͑ͯΔͷ͸ RightProjection!!!!!
  31. for-comprehensionͰ ୅ೖͬΆ͍͜ͱ͕Ͱ͖ͳ͍ ɾ(Right|Left)Projection.map() ͕ฦ͢ܕ͸ Either ɾ͔͠͠ Either ʹ͸ map ΋

    flatMap ΋ੜ͑ͯͳ͍ ɾEither ʹ map ͱ͔͕ੜ͑ͯͨΒྑ͍ͷʹ…
  32. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ for { (a, b) <- Right((1, 2)).right }

    yield a + b ͍͍ͩͨ͜Μͳײ͡ʹͳΔͬΆ͍ Right((1, 2)).right.filter(_ match { case (_, _) => true case _ => false }).map(_ match { case (a, b) => a + b })
  33. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ Right((1, 2)).right.filter(_ match { case (_, _) =>

    true case _ => false }).map(_ match { case (a, b) => a + b }) λϓϧ͕λϓϧ͔ΛXJUI'JMUFSͰݕࠪ
  34. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ Right((1, 2)).right.filter(_ match { case (_, _) =>

    true case _ => false }).map(_ match { case (a, b) => a + b }) <console>:19: error: constructor cannot be instantiated to expected type; found : (T1, T2) required: scala.util.Either[Nothing,(Int, Int)] (a, b) <- Right((1, 2)).right ^
  35. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ RightProjection.filter ͷ࣮૷ΛݟͯΈΔͱ def filter[X](p: B => Boolean): Option[Either[X,

    B]] = e match { case Left(_) => None case Right(b) => if(p(b)) Some(Right(b)) else None } https://github.com/scala/scala/blob/d6f66ec0f38e42c19f79cbe9d32d29c65dee1e05/src/library/ scala/util/Either.scala#L546-L549
  36. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ RightProjection.filter ͷ࣮૷ΛݟͯΈΔͱ def filter[X](p: B => Boolean): Option[Either[X,

    B]] = e match { case Left(_) => None case Right(b) => if(p(b)) Some(Right(b)) else None } https://github.com/scala/scala/blob/d6f66ec0f38e42c19f79cbe9d32d29c65dee1e05/src/library/ scala/util/Either.scala#L546-L549
  37. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ Right((1, 2)).right.filter(_ match { case (_, _) =>

    true case _ => false }).map(_ match { case (a, b) => a + b }) <console>:19: error: constructor cannot be instantiated to expected type; found : (T1, T2) required: scala.util.Either[Nothing,(Int, Int)] (a, b) <- Right((1, 2)).right ^ Either[Nothing, (Int, Int)]
  38. / || ̄ ̄|| ∧_∧ |.....||__|| (     )  どうしてこうなった・・・ | ̄ ̄\三⊂/ ̄ ̄ ̄/ |    | ( ./     /  ___

  39. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ ɾfilter ͕ Option[Either[X,B]] Λฦ͢ͷ͕ݪҼ ɾfilter ͕ Either[X,B] Λฦͯ͘͠ΕΔͱOK

    ɾfilter ʹҾ͔͔ͬΒͳ͔ͬͨͱ͖ʹʮࣗવͳʯLeft஋Λ ఆٛͰ͖Δͱྑͦ͞͏ ɾEither[String, B] ͳΒ Left(“”) ɾEither[Int, B] ͳΒ Left(0) ɾΈ͍ͨʹฦ͢ͱࣗવͬΆ͘ͳ͍ʁ
  40. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ ๻ͷߟ͍͖͑ͨ͞ΐʔͷfilter(ະ׬) def filter[X](p: B => Boolean): Either[X, B]

    = e match { case Left(e) => Left(e) case Right(b) => if(p(b)) Right(b) ɹɹ else Left(<͍͍ײ͡ͷ஋>: X) }
  41. ͓͠ͳ͕͖ 1. ࣗݾ঺հ 2. scala.Either ֓ཁ 3. scala.Either ͷෆศ 4.

    ෆศͷݪҼ 5. scalaz.\/
  42. ͜Ε·Ͱͷ·ͱΊ ɾRightProjection Ͱͳ͘ Either ʹ map/flatMap ͕ੜ͑ͯΕ͹خ͍͠ ɾfilter ͕ Either[X,B]

    Λฦͯ͠ཉ͍͠ ɾͦͷͨΊ filter ͰϚον͠ͳ͔ͬͨͱ͖ʹࣗવͳ Left஋ΛͱΔૢ࡞͕Ͱ͖Δͱྑͦ͞͏
  43. scalaz ɾศརܕΫϥε ɾศརσʔλܕ ɾඪ४Ϋϥε֦ுͷͨΊͷศར implicit conversion ͕ू߹ͨ͠ศརϥΠϒϥϦ(ͱ͍͏ೝࣝ)

  44. scalaz.\/ sealed abstract class \/[+A, +B] extends Product with Serializable

    final case class -\/[+A](a: A) extends (A \/ Nothing) final case class \/-[+B](b: B) extends (Nothing \/ B) scala.Either ͱҧͬͯ scalaz.\/ ʹ͸ map ΍ flatMap ͕ੜ ͑ͯΔʂ
  45. for-comprehensionͰ ୅ೖͬΆ͍͜ͱ͕Ͱ͖ͳ͍ scalaz.\/ ʹ͸ map ΍ flatMap ͕ੜ͑ͯΔʂʂ for {

    a <- 1.right[String] b = a + 1 } yield b res3: scalaz.\/[String,Int] = \/-(2)
  46. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ ͓͞Β͍: RightProjection.filter ͷ࣮૷ def filter[X](p: B => Boolean):

    Option[Either[X, B]] = e match { case Left(_) => None case Right(b) => if(p(b)) Some(Right(b)) else None }
  47. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ ๻ͷߟ͍͖͑ͨ͞ΐʔͷfilter def filter[X](p: B => Boolean): Either[X, B]

    = e match { case Left(e) => Left(e) case Right(b) => if(p(b)) Right(b) ɹɹ else Left(<͍͍ײ͡ͷ஋>: X) }
  48. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ scalaz.\/.filter ͷ࣮૷͸ def filter[AA >: A](p: B =>

    Boolean) (implicit M: Monoid[AA]): (AA \/ B) = this match { case -\/(_) => this case \/-(b) => if(p(b)) this else -\/(M.zero) } https://github.com/scalaz/scalaz/blob/series/7.3.x/core/src/main/scala/scalaz/ Either.scala#L145-L150
  49. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ Monoid : (Monad͡Όͳ͍Αʂ) ू߹(ܕ)Sͱͦͷ্ͷೋ߲ԋࢉ |+| ʹ͍ͭͯҎԼͷنଇΛຬͨ͢ ू߹ͱೋ߲ԋࢉͷ૊Έ߹Θͤ 1.

    ೋ߲ԋࢉ ͕ू߹ʹ͍ͭͯด͍ͯ͡Δ (ೋ߲ԋࢉͷҾ਺ͱฦΓ஋ͷܕ͕ಉ͡) 2. ԋࢉ͕݁߹཯Λຬͨ͢ (a |+| b) |+| c == a |+| (b |+| c) 3. ୯Ґݩe ͕ଘࡏ͢Δ (forall s: S) s |+| e == e && e |+| s == e ࠓճॏཁͳͷ͸ ͜ͷੑ࣭ʂʂ
  50. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ ྫ: Int ͱ + ͳΒ୯Ґݩ͸ 0 0 +

    x = x + 0 = x (where x: Int) String ͱ + ͳΒ୯Ґݩ͸ “” “” + s = s + “” = s (where s: String)
  51. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ Monoid[X].zero ͰܕXͷ(Ճ๏ʹ͍ͭͯͷ(?))୯ҐݩΛͱΔ Monoid[Int].zero = 0 Monoid[String].zero = “”

    Monoid[List[Int]] = List() Ͳ͜Ͱఆٛ͞ΕͯΔͷ͔
  52. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ Int΍ΒString΍Β͍ΖΜͳܕͷMonoidͱͯ͠ͷੑ࣭͕ implicit object ͱͯ͠ scalaz಺Ͱఆٛ͞ΕͯΔ trait StringInstances {

    implicit object stringInstance extends Monoid[String] with /*தུ*/ { // தུ def zero: String = "" // தུ } } https://github.com/scalaz/scalaz/blob/series/7.3.x/core/src/main/scala/scalaz/std/ String.scala#L5
  53. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ scalaz.\/.filter ͷ࣮૷͸ def filter[AA >: A](p: B =>

    Boolean) (implicit M: Monoid[AA]): (AA \/ B) = this match { case -\/(_) => this case \/-(b) => if(p(b)) this else -\/(M.zero) } aʹͳΔ͍ΖΜͳܕʹ͍ͭͯ౷Ұతͳ ΠϯλʔϑΣʔε .POPJE<9>[FSP  ͰྵݩΛฦ͢͜ͱ͕Ͱ͖Δ
  54. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ 1.right[String].filter(_ > 0) res25: scalaz.\/[String,Int] = \/-(1) 1.right[String].filter(_

    < 0) res26: scalaz.\/[String,Int] = -\/()
  55. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ for { (a, b) <- (1, 2).right[String] }

    yield a + b res27: scalaz.\/[String,Int] = \/-(3) (warning͕ग़·͕͢withFilterͷ୅ΘΓʹfilterΛ࢖ͬͨͧʂͬͯ ͍͏ܯࠂ) OK͡ΌΜʂʂ
  56. ·ͱΊ ɾscala.Either ʹ͸ෆࣗવͳڍಈ͕͍͔ͭ͋͘Δ ɾͦͷҰͭͷղܾࡦͱͯ͠ scalaz.\/ Λ࢖͏ͱ͍͏બ୒ࢶ͕ ͋Δ ɾ؆୯ͳͱ͜Ζ(\/)͔Β scalaz ࢖͍ͬͯ͘ͷ͸ྑͦ͞͏

    ɾศརͳͱ͜Ζ͚ͩ࢖͓͏ʂ ɾେࣄͳͷ͸ scala.Either ͷڍಈΛ஌͓ͬͯ͘͜ͱʂ
  57. ࢀߟ HaskellͷdoͱScalaͷforࣜͱEitherͱMonadPlus http://d.hatena.ne.jp/xuwei/20130517/1368814058 ओཁͳܕΫϥεͷ঺հ https://gist.github.com/gakuzzzz/8d497609012863b3ea50 scalaz https://github.com/scalaz/scalaz ಠश Scalaz —

    \/ http://eed3si9n.com/learning-scalaz/ja/Either.html