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

scalaz.\/ が便利だった話

scalaz.\/ が便利だった話

Rikito Taniguchi

July 10, 2016
Tweet

More Decks by Rikito Taniguchi

Other Decks in Programming

Transcript

  1. 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
  2. Either def parseInteger(numStr: String): Either[NumberFormatException, Int] = { try {

    Right(numStr.toInt) } catch { case e: NumberFormatException => Left(e) } } ྫ֎Λ&JUIFSͰϥοϓͯ͠ΈͨΓ
  3. 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")
  4. Either - ֬ೝ scala ͷ forࣜ͸ίϯύΠϧ࣌ʹ಺෦తʹ map / flatMap /

    withFilter / filter / foreach ͱ͍ͬͨϝιουͷ૊Έ߹Θͤʹม׵͞ΕΔ
  5. 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͔Βग़͖ͯͨ஋Λӈࣜʹ࣋ͭ࣌
  6. 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 ^
  7. 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) ύλʔϯϚον͡Όͳ͍͚Ͳ͜Ε΋μϝ
  8. ͪͳΈʹ྆ํͱ΋ 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)
  9. ֬ೝ scala.Either ΍ scalaz.\/ ʹ͸ withFilter ͕࣮૷ ͞Ε͓ͯΒͣ withFilter ͷ୅ΘΓʹ

    filter ͕࢖༻͞ ΕΔ ࠓճͷ࿩Ͱ͸ filter ͱ withFilter ͷҧ͍͸ॏཁͰ͸ ͳ͍ͷͰ໨ΛͭΉΓ·͢
  10. 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 })
  11. for-comprehensionͰ ୅ೖͬΆ͍͜ͱ͕Ͱ͖ͳ͍ Right(1).right.map(a => { val b = a +

    1; (a, b) }).map(_ match { case ((a, b)) => b }) ͜͜ͷฦΓ஋͸ Right((1, 2))
  12. 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!!!!!
  13. 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 })
  14. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ Right((1, 2)).right.filter(_ match { case (_, _) =>

    true case _ => false }).map(_ match { case (a, b) => a + b }) λϓϧ͕λϓϧ͔ΛXJUI'JMUFSͰݕࠪ
  15. 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 ^
  16. 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
  17. 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
  18. 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)]
  19. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ ɾfilter ͕ Option[Either[X,B]] Λฦ͢ͷ͕ݪҼ ɾfilter ͕ Either[X,B] Λฦͯ͘͠ΕΔͱOK

    ɾfilter ʹҾ͔͔ͬΒͳ͔ͬͨͱ͖ʹʮࣗવͳʯLeft஋Λ ఆٛͰ͖Δͱྑͦ͞͏ ɾEither[String, B] ͳΒ Left(“”) ɾEither[Int, B] ͳΒ Left(0) ɾΈ͍ͨʹฦ͢ͱࣗવͬΆ͘ͳ͍ʁ
  20. 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) }
  21. ͜Ε·Ͱͷ·ͱΊ ɾRightProjection Ͱͳ͘ Either ʹ map/flatMap ͕ੜ͑ͯΕ͹خ͍͠ ɾfilter ͕ Either[X,B]

    Λฦͯ͠ཉ͍͠ ɾͦͷͨΊ filter ͰϚον͠ͳ͔ͬͨͱ͖ʹࣗવͳ Left஋ΛͱΔૢ࡞͕Ͱ͖Δͱྑͦ͞͏
  22. 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 ͕ੜ ͑ͯΔʂ
  23. for-comprehensionͰ ୅ೖͬΆ͍͜ͱ͕Ͱ͖ͳ͍ scalaz.\/ ʹ͸ map ΍ flatMap ͕ੜ͑ͯΔʂʂ for {

    a <- 1.right[String] b = a + 1 } yield b res3: scalaz.\/[String,Int] = \/-(2)
  24. 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 }
  25. 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) }
  26. 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
  27. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ Monoid : (Monad͡Όͳ͍Αʂ) ू߹(ܕ)Sͱͦͷ্ͷೋ߲ԋࢉ |+| ʹ͍ͭͯҎԼͷنଇΛຬͨ͢ ू߹ͱೋ߲ԋࢉͷ૊Έ߹Θͤ 1.

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

    x = x + 0 = x (where x: Int) String ͱ + ͳΒ୯Ґݩ͸ “” “” + s = s + “” = s (where s: String)
  29. 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
  30. 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  ͰྵݩΛฦ͢͜ͱ͕Ͱ͖Δ
  31. for-comprehensionͰ ύλʔϯϚονͰ͖ͳ͍໰୊ for { (a, b) <- (1, 2).right[String] }

    yield a + b res27: scalaz.\/[String,Int] = \/-(3) (warning͕ग़·͕͢withFilterͷ୅ΘΓʹfilterΛ࢖ͬͨͧʂͬͯ ͍͏ܯࠂ) OK͡ΌΜʂʂ